improved scaling for monochrome images
[swftools.git] / lib / modules / swfbits.c
1 /* swfbits.c
2
3    Bitmap functions (needs libjpeg) 
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #define OUTBUFFER_SIZE 0x8000
25
26 int swf_ImageHasAlpha(RGBA*img, int width, int height)
27 {
28     int len = width*height;
29     int t;
30     int hasalpha=0;
31     for(t=0;t<len;t++) {
32         if(img[t].a >= 4 && img[t].a < 0xfc)
33             return 2;
34         if(img[t].a < 4)
35             hasalpha=1;
36     }
37     return hasalpha;
38 }
39
40 int swf_ImageGetNumberOfPaletteEntries2(RGBA*_img, int width, int height)
41 {
42     int len = width*height;
43     int t;
44     U32* img = (U32*)_img;
45     U32 color1 = img[0];
46     U32 color2 = 0;
47     for(t=1;t<len;t++) {
48         if(img[t] != color1) {
49             color2 = img[t];
50             break;
51         }
52     }
53     if(t==len)
54         return 1;
55
56     for(;t<len;t++) {
57         if(img[t] != color1 && img[t] != color2) {
58             return width*height;
59         }
60     }
61     return 2;
62 }
63
64 /*int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
65 {
66     int len = width*height;
67     int t;
68     int palsize = 0;
69     RGBA pal[512];
70     U32*pal32=(U32*)pal;
71     int palette_overflow = 0;
72     U32 lastcol32 = 0;
73
74     if(sizeof(RGBA)!=sizeof(U32))
75         fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
76
77     lastcol32 = pal32[palsize++] = *(U32*)&img[0];
78
79     for(t=1;t<len;t++) {
80         RGBA col = img[t];
81         U32 col32 = *(U32*)&img[t];
82         int i;
83         if(col32==lastcol32)
84             continue;
85         for(i=0;i<palsize;i++) {
86             if(col32 == pal32[i])
87                 break;
88         }
89         if(i==palsize) {
90             if(palsize==512) {
91                 palette_overflow = 1;
92                 break;
93             }
94             pal32[palsize++] = col32;
95         }
96         lastcol32 = col32;
97     }
98     if(palette_overflow)
99         return width*height;
100     if(palette)
101         memcpy(palette, pal, palsize*sizeof(RGBA));
102     return palsize;
103 }*/
104
105 int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
106 {
107     int len = width*height;
108     int t;
109     int palsize = 0;
110     U32* pal;
111     int size[256];
112     int palette_overflow = 0;
113     U32 lastcol32 = 0;
114
115     pal = malloc(65536*sizeof(U32));
116
117     memset(size, 0, sizeof(size));
118
119     if(sizeof(RGBA)!=sizeof(U32))
120         fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
121
122     lastcol32 = (*(U32*)&img[0])^0xffffffff; // don't match
123
124     for(t=0;t<len;t++) {
125         RGBA col = img[t];
126         U32 col32 = *(U32*)&img[t];
127         int i;
128         int csize;
129         U32 hash;
130         U32* cpal;
131         if(col32 == lastcol32)
132             continue;
133         hash = (col32 >> 17) ^ col32;
134         hash ^= ((hash>>8) + 1) ^ hash;
135         hash &= 255;
136
137         csize = size[hash];
138         cpal = &pal[hash*256];
139         for(i=0;i<csize;i++) {
140             if(col32 == cpal[i])
141                 break;
142         }
143         if(i==csize) {
144             if(palsize==256) {
145                 palette_overflow = 1;
146                 break;
147             }
148             cpal[size[hash]++] = col32;
149             palsize++;
150         }
151         lastcol32 = col32;
152     }
153     if(palette_overflow) {
154         free(pal);
155         return width*height;
156     }
157     if(palette) {
158         int i = 0;
159         for(t=0;t<256;t++) {
160             int s;
161             int csize = size[t];
162             U32* cpal = &pal[t*256];
163             for(s=0;s<csize;s++)
164                 palette[i++] = *(RGBA*)(&cpal[s]);
165         }
166     }
167     free(pal);
168     return palsize;
169 }
170
171
172
173 #ifdef HAVE_JPEGLIB
174
175 typedef struct _JPEGDESTMGR {
176     struct jpeg_destination_mgr mgr;
177     TAG *t;
178     JOCTET *buffer;
179     struct jpeg_compress_struct cinfo;
180     struct jpeg_error_mgr jerr;
181 } JPEGDESTMGR, *LPJPEGDESTMGR;
182
183 // Destination manager callbacks
184
185 static void RFXSWF_init_destination(j_compress_ptr cinfo)
186 {
187     JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
188     dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
189     dmgr->mgr.next_output_byte = dmgr->buffer;
190     dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
191 }
192
193 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
194 {
195     JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
196     swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
197     dmgr->mgr.next_output_byte = dmgr->buffer;
198     dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
199     return TRUE;
200 }
201
202 static void RFXSWF_term_destination(j_compress_ptr cinfo)
203 {
204     JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
205     swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
206                  OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
207     rfx_free(dmgr->buffer);
208     dmgr->mgr.free_in_buffer = 0;
209 }
210
211 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
212 {
213     JPEGDESTMGR *jpeg;
214
215     // redirect compression lib output to local SWF Tag structure
216
217     jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
218
219     jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
220
221     jpeg_create_compress(&jpeg->cinfo);
222
223     jpeg->mgr.init_destination = RFXSWF_init_destination;
224     jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
225     jpeg->mgr.term_destination = RFXSWF_term_destination;
226
227     jpeg->t = t;
228
229     jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
230
231     // init compression
232
233     jpeg->cinfo.image_width = width;
234     jpeg->cinfo.image_height = height;
235     jpeg->cinfo.input_components = 3;
236     jpeg->cinfo.in_color_space = JCS_RGB;
237
238     jpeg_set_defaults(&jpeg->cinfo);
239     jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
240
241     // write tables to SWF
242
243     jpeg_write_tables(&jpeg->cinfo);
244
245     // compess image to SWF
246
247     jpeg_suppress_tables(&jpeg->cinfo, TRUE);
248     jpeg_start_compress(&jpeg->cinfo, FALSE);
249
250     return (JPEGBITS *) jpeg;
251 }
252
253 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
254 {
255     JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
256     if (!jpeg)
257         return -1;
258     jpeg_write_scanlines(&jpeg->cinfo, data, n);
259     return 0;
260 }
261
262 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
263 {
264     return swf_SetJPEGBitsLines(jpegbits, &data, 1);
265 }
266
267 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
268 {
269     JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
270     if (!jpeg)
271         return -1;
272     jpeg_finish_compress(&jpeg->cinfo);
273     rfx_free(jpeg);
274     return 0;
275 }
276
277 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
278                       int quality)
279 {
280     JPEGBITS *jpeg;
281     int y;
282     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
283     for (y = 0; y < height; y++) {
284         U8 scanline[3 * width];
285         int x, p = 0;
286         for (x = 0; x < width; x++) {
287             scanline[p++] = bitmap[width * y + x].r;
288             scanline[p++] = bitmap[width * y + x].g;
289             scanline[p++] = bitmap[width * y + x].b;
290         }
291         swf_SetJPEGBitsLine(jpeg, scanline);
292     }
293     swf_SetJPEGBitsFinish(jpeg);
294 }
295
296 void swf_GetJPEGSize(char *fname, int *width, int *height)
297 {
298     struct jpeg_decompress_struct cinfo;
299     struct jpeg_error_mgr jerr;
300     FILE *fi;
301     *width = 0;
302     *height = 0;
303     cinfo.err = jpeg_std_error(&jerr);
304     jpeg_create_decompress(&cinfo);
305     if ((fi = fopen(fname, "rb")) == NULL) {
306         fprintf(stderr, "rfxswf: file open error\n");
307         return;
308     }
309     jpeg_stdio_src(&cinfo, fi);
310     jpeg_read_header(&cinfo, TRUE);
311     *width = cinfo.image_width;
312     *height = cinfo.image_height;
313     jpeg_destroy_decompress(&cinfo);
314     fclose(fi);
315 }
316
317 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
318 {
319     struct jpeg_decompress_struct cinfo;
320     struct jpeg_error_mgr jerr;
321     JPEGBITS *out;
322     FILE *f;
323     U8 *scanline;
324
325     cinfo.err = jpeg_std_error(&jerr);
326     jpeg_create_decompress(&cinfo);
327
328     if ((f = fopen(fname, "rb")) == NULL) {
329         fprintf(stderr, "rfxswf: file open error\n");
330         return -1;
331     }
332
333     jpeg_stdio_src(&cinfo, f);
334     jpeg_read_header(&cinfo, TRUE);
335     jpeg_start_decompress(&cinfo);
336
337     out =
338         swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
339                              quality);
340     scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
341
342     if (scanline) {
343         int y;
344         U8 *js = scanline;
345         if (cinfo.out_color_space == JCS_GRAYSCALE) {
346             for (y = 0; y < cinfo.output_height; y++) {
347                 int x;
348                 jpeg_read_scanlines(&cinfo, &js, 1);
349                 for (x = cinfo.output_width - 1; x >= 0; x--) {
350                     js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
351                 }
352                 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
353             }
354         } else if (cinfo.out_color_space == JCS_RGB) {
355             for (y = 0; y < cinfo.output_height; y++) {
356                 jpeg_read_scanlines(&cinfo, &js, 1);
357                 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
358             }
359         } else if (cinfo.out_color_space == JCS_YCCK) {
360             //FIXME
361             fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
362             return -1;
363         } else if (cinfo.out_color_space == JCS_YCbCr) {
364             for (y = 0; y < cinfo.output_height; y++) {
365                 int x;
366                 for (x = 0; x < cinfo.output_width; x++) {
367                     int y = js[x * 3 + 0];
368                     int u = js[x * 3 + 1];
369                     int v = js[x * 3 + 1];
370                     js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
371                     js[x * 3 + 1] =
372                         y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
373                     js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
374                 }
375             }
376         } else if (cinfo.out_color_space == JCS_CMYK) {
377             for (y = 0; y < cinfo.output_height; y++) {
378                 int x;
379                 jpeg_read_scanlines(&cinfo, &js, 1);
380                 /* This routine seems to work for now-
381                    It's a mixture of 3 different
382                    CMYK->RGB conversion routines I found in the
383                    web. (which all produced garbage)
384                    I'm happily accepting suggestions. (mk) */
385                 for (x = 0; x < cinfo.output_width; x++) {
386                     int white = 255 - js[x * 4 + 3];
387                     js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
388                     js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
389                     js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
390                 }
391                 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
392             }
393         }
394     }
395
396     swf_SetJPEGBitsFinish(out);
397     jpeg_finish_decompress(&cinfo);
398     fclose(f);
399
400     return 0;
401 }
402
403 typedef struct _JPEGFILEMGR {
404     struct jpeg_destination_mgr mgr;
405     JOCTET *buffer;
406     struct jpeg_compress_struct* cinfo;
407     struct jpeg_error_mgr* jerr;
408     FILE*fi;
409 } JPEGFILEMGR;
410
411 static void file_init_destination(j_compress_ptr cinfo) 
412
413     JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
414     struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
415
416     fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
417     if(!fmgr->buffer) {
418         perror("malloc");
419         fprintf(stderr, "Out of memory!\n");
420         exit(1);
421     }
422
423     dmgr->next_output_byte = fmgr->buffer;
424     dmgr->free_in_buffer = OUTBUFFER_SIZE;
425 }
426
427 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
428
429     JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
430     struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
431
432     if(fmgr->fi)
433         fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
434
435     dmgr->next_output_byte = fmgr->buffer;
436     dmgr->free_in_buffer = OUTBUFFER_SIZE;
437     return 1;
438 }
439
440 static void file_term_destination(j_compress_ptr cinfo) 
441
442     JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
443     struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
444
445     if(fmgr->fi)
446         fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
447
448     rfx_free(fmgr->buffer);
449     fmgr->buffer = 0;
450     dmgr->free_in_buffer = 0;
451     dmgr->next_output_byte = 0;
452 }
453
454 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
455 {
456     JPEGFILEMGR fmgr;
457     struct jpeg_compress_struct cinfo;
458     struct jpeg_error_mgr jerr;
459     unsigned char*data2 = 0;
460     int y;
461
462     FILE*fi = fopen(filename, "wb");
463     if(!fi) {
464         char buf[256];
465         sprintf(buf, "rfxswf: Couldn't create %s", filename);
466         perror(buf);
467         return;
468     }
469     data2 = rfx_calloc(width*3);
470
471     memset(&cinfo, 0, sizeof(cinfo));
472     memset(&jerr, 0, sizeof(jerr));
473     memset(&fmgr, 0, sizeof(fmgr));
474     cinfo.err = jpeg_std_error(&jerr);
475     jpeg_create_compress(&cinfo);
476
477     fmgr.mgr.init_destination = file_init_destination;
478     fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
479     fmgr.mgr.term_destination = file_term_destination;
480     fmgr.fi = fi;
481     fmgr.cinfo = &cinfo;
482     fmgr.jerr = &jerr;
483     cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
484
485     // init compression
486
487     cinfo.image_width  = width;
488     cinfo.image_height = height;
489     cinfo.input_components = 3;
490     cinfo.in_color_space = JCS_RGB;
491     jpeg_set_defaults(&cinfo);
492     cinfo.dct_method = JDCT_IFAST;
493     jpeg_set_quality(&cinfo,quality,TRUE);
494
495     //jpeg_write_tables(&cinfo);
496     //jpeg_suppress_tables(&cinfo, TRUE);
497     jpeg_start_compress(&cinfo, FALSE);
498
499     for(y=0;y<height;y++) {
500         int x;
501         RGBA*src = &pixels[y*width];
502         for(x=0;x<width;x++) {
503             data2[x*3+0] = src[x].r;
504             data2[x*3+1] = src[x].g;
505             data2[x*3+2] = src[x].b;
506         }
507         jpeg_write_scanlines(&cinfo, &data2, 1);
508     }
509     rfx_free(data2);
510     jpeg_finish_compress(&cinfo);
511     jpeg_destroy_compress(&cinfo);
512
513     fclose(fi);
514 }
515
516 /*  jpeg_source_mgr functions */
517 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
518 {
519     TAG *tag = (TAG *) cinfo->client_data;
520     if (tag->id == ST_DEFINEBITSJPEG3) {
521         swf_SetTagPos(tag, 6);
522     } else {
523         swf_SetTagPos(tag, 2);
524     }
525     cinfo->src->bytes_in_buffer = 0;
526 }
527 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
528 {
529     TAG *tag = (TAG *) cinfo->client_data;
530     if (tag->data[tag->pos + 0] == 0xff &&
531         tag->data[tag->pos + 1] == 0xd9 &&
532         tag->data[tag->pos + 2] == 0xff &&
533         tag->data[tag->pos + 3] == 0xd8) {
534         tag->pos += 4;
535     }
536     if (tag->pos >= tag->len) {
537         cinfo->src->next_input_byte = 0;
538         cinfo->src->bytes_in_buffer = 0;
539         return 0;
540     }
541     cinfo->src->next_input_byte = &tag->data[tag->pos];
542     cinfo->src->bytes_in_buffer = 1;    //tag->len - tag->pos;
543     tag->pos += 1;
544     return 1;
545 }
546 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
547 {
548     TAG *tag = (TAG *) cinfo->client_data;
549     cinfo->src->next_input_byte = 0;
550     cinfo->src->bytes_in_buffer = 0;
551     tag->pos += count;
552 }
553 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
554 {
555     return jpeg_resync_to_restart(cinfo, desired);
556 }
557 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
558 {
559     TAG *tag = (TAG *) cinfo->client_data;
560 }
561 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
562 {
563     struct jpeg_decompress_struct cinfo;
564     struct jpeg_error_mgr jerr;
565     struct jpeg_source_mgr mgr;
566     RGBA *dest;
567     int y;
568     int offset = 0;
569     int oldtaglen = 0;
570     *width = 0;
571     *height = 0;
572
573     if (tag->id == ST_DEFINEBITSJPEG) {
574         fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
575         return 0;
576     }
577     if (tag->id == ST_DEFINEBITSJPEG3) {
578 #ifdef HAVE_ZLIB
579         offset = swf_GetU32(tag);
580         oldtaglen = tag->len;
581         tag->len = offset+6;
582 #else
583         fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
584         return 0;
585 #endif
586     }
587
588     cinfo.err = jpeg_std_error(&jerr);
589     jpeg_create_decompress(&cinfo);
590
591     cinfo.client_data = (void *) tag;
592     cinfo.src = &mgr;
593     cinfo.src->init_source = tag_init_source;
594     cinfo.src->fill_input_buffer = tag_fill_input_buffer;
595     cinfo.src->skip_input_data = tag_skip_input_data;
596     cinfo.src->resync_to_restart = jpeg_resync_to_restart;
597     cinfo.src->term_source = tag_term_source;
598     cinfo.out_color_space = JCS_RGB;
599
600     jpeg_read_header(&cinfo, TRUE);
601     *width = cinfo.image_width;
602     *height = cinfo.image_height;
603     dest =
604         rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
605
606     jpeg_start_decompress(&cinfo);
607     for (y = 0; y < cinfo.output_height; y++) {
608         RGBA *line = &dest[y * cinfo.image_width];
609         U8 *to = (U8 *) line;
610         int x;
611         jpeg_read_scanlines(&cinfo, &to, 1);
612         for (x = cinfo.output_width - 1; x >= 0; --x) {
613             int r = to[x * 3 + 0];
614             int g = to[x * 3 + 1];
615             int b = to[x * 3 + 2];
616             line[x].r = r;
617             line[x].g = g;
618             line[x].b = b;
619             line[x].a = 255;
620         }
621     }
622
623     jpeg_finish_decompress(&cinfo);
624
625     jpeg_destroy_decompress(&cinfo);
626
627 #ifdef HAVE_ZLIB
628     if(offset) {
629         U32 datalen = cinfo.output_width*cinfo.output_height;
630         U8* alphadata = (U8*)rfx_alloc(datalen);
631         int error;
632         tag->len = oldtaglen;
633         swf_SetTagPos(tag, 6+offset);
634         error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
635         if (error != Z_OK) {
636             fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
637             return 0;
638         }
639         for(y=0;y<cinfo.output_height;y++) {
640             RGBA*line = &dest[y*cinfo.output_width];
641             U8*aline = &alphadata[y*cinfo.output_width];
642             int x;
643             for(x=0;x<cinfo.output_width;x++) {
644                 line[x].a = aline[x];
645             }
646         }
647         free(alphadata);
648     }
649 #endif
650     return dest;
651 }
652
653 #endif                          // HAVE_JPEGLIB
654
655 // Lossless compression texture based on zlib
656
657 #ifdef HAVE_ZLIB
658
659 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
660 {
661     U8 *data = rfx_alloc(OUTBUFFER_SIZE);
662     zs->next_out = data;
663     zs->avail_out = OUTBUFFER_SIZE;
664     while (1) {
665         int status = deflate(zs, Z_NO_FLUSH);
666
667         if (status != Z_OK) {
668             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
669             rfx_free(data);
670             return status;
671         }
672
673         if (zs->next_out != data) {
674             swf_SetBlock(t, data, zs->next_out - data);
675             zs->next_out = data;
676             zs->avail_out = OUTBUFFER_SIZE;
677         }
678
679         if (zs->avail_in == 0)
680             break;
681     }
682
683     if (!finish) {
684         rfx_free(data);
685         return 0;
686     }
687
688     while (1) {
689         int status = deflate(zs, Z_FINISH);
690         if (status != Z_OK && status != Z_STREAM_END) {
691             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
692             rfx_free(data);
693             return status;
694         }
695
696         if (zs->next_out != data) {
697             swf_SetBlock(t, data, zs->next_out - data);
698             zs->next_out = data;
699             zs->avail_out = OUTBUFFER_SIZE;
700         }
701
702         if (status == Z_STREAM_END)
703             break;
704     }
705     rfx_free(data);
706     return 0;
707 }
708
709
710 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
711 {
712     int res = 0;
713     int bps;
714
715     switch (bitmap_flags) {
716     case BMF_8BIT:
717         return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
718     case BMF_16BIT:
719         bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
720         break;
721     case BMF_32BIT:
722         bps = width * 4;
723         break;
724     default:
725         fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
726         return -1;
727     }
728
729     swf_SetU8(t, bitmap_flags);
730     swf_SetU16(t, width);
731     swf_SetU16(t, height);
732
733     {
734         z_stream zs;
735
736         memset(&zs, 0x00, sizeof(z_stream));
737         zs.zalloc = Z_NULL;
738         zs.zfree = Z_NULL;
739
740         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
741             zs.avail_in = bps * height;
742             zs.next_in = bitmap;
743
744             if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
745                 res = -3;
746             deflateEnd(&zs);
747
748         } else
749             res = -3;           // zlib error
750     }
751     return res;
752 }
753
754 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
755 {
756     RGBA *pal = palette;
757     int bps = BYTES_PER_SCANLINE(width);
758     int res = 0;
759
760     if (!pal)                   // create default palette for grayscale images
761     {
762         int i;
763         pal = rfx_alloc(256 * sizeof(RGBA));
764         for (i = 0; i < 256; i++) {
765             pal[i].r = pal[i].g = pal[i].b = i;
766             pal[i].a = 0xff;
767         }
768         ncolors = 256;
769     }
770
771     if ((ncolors < 2) || (ncolors > 256) || (!t)) {
772         fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
773                 ncolors);
774         return -1;              // parameter error
775     }
776
777     swf_SetU8(t, BMF_8BIT);
778     swf_SetU16(t, width);
779     swf_SetU16(t, height);
780     swf_SetU8(t, ncolors - 1);  // number of pal entries
781
782     {
783         z_stream zs;
784
785         memset(&zs, 0x00, sizeof(z_stream));
786         zs.zalloc = Z_NULL;
787         zs.zfree = Z_NULL;
788
789         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
790             U8 *zpal;           // compress palette
791             if ((zpal = rfx_alloc(ncolors * 4))) {
792                 U8 *pp = zpal;
793                 int i;
794
795                 /* be careful with ST_DEFINEBITSLOSSLESS2, because
796                    the Flash player produces great bugs if you use too many
797                    alpha colors in your palette. The only sensible result that
798                    can be archeived is setting one color to r=0,b=0,g=0,a=0 to
799                    make transparent parts in sprites. That's the cause why alpha
800                    handling is implemented in lossless routines of rfxswf.
801
802                    Indeed: I haven't understood yet how flash player handles
803                    alpha values different from 0 and 0xff in lossless bitmaps...
804                  */
805
806                 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2)  // have alpha channel?
807                 {
808                     for (i = 0; i < ncolors; i++) {
809                         pp[0] = pal[i].r;
810                         pp[1] = pal[i].g;
811                         pp[2] = pal[i].b;
812                         pp[3] = pal[i].a;
813                         pp += 4;
814                     }
815                     zs.avail_in = 4 * ncolors;
816                 } else {
817                     for (i = 0; i < ncolors; i++)       // pack RGBA structures to RGB 
818                     {
819                         pp[0] = pal[i].r;
820                         pp[1] = pal[i].g;
821                         pp[2] = pal[i].b;
822                         pp += 3;
823                     }
824                     zs.avail_in = 3 * ncolors;
825                 }
826
827                 zs.next_in = zpal;
828
829                 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
830                     res = -3;
831
832                 // compress bitmap
833                 zs.next_in = bitmap;
834                 zs.avail_in = (bps * height * sizeof(U8));
835
836                 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
837                     res = -3;
838
839                 deflateEnd(&zs);
840
841                 rfx_free(zpal);
842             } else
843                 res = -2;       // memory error
844         } else
845             res = -3;           // zlib error
846     }
847
848     if (!palette)
849         rfx_free(pal);
850
851     return res;
852 }
853
854 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
855 {
856     return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
857 }
858
859 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
860 {
861     int num = width*height;
862     int t;
863     for(t=0;t<num;t++) {
864         data[t].r = ((int)data[t].r*data[t].a)/255;
865         data[t].g = ((int)data[t].g*data[t].a)/255;
866         data[t].b = ((int)data[t].b*data[t].a)/255;
867     }
868 }
869
870 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
871 {
872     int hasalpha = swf_ImageHasAlpha(data, width, height);
873     int num;
874     if(!hasalpha) {
875         tag->id = ST_DEFINEBITSLOSSLESS;
876     } else {
877         tag->id = ST_DEFINEBITSLOSSLESS2;
878         swf_PreMultiplyAlpha(data, width, height);
879     }
880     num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
881     if(num>1 && num<=256) {
882         RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
883         int width2 = BYTES_PER_SCANLINE(width);
884         U8*data2 = (U8*)malloc(width2*height);
885         int len = width*height;
886         int x,y;
887         int r;
888         swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
889         for(y=0;y<height;y++) {
890             RGBA*src = &data[width*y];
891             U8*dest = &data2[width2*y];
892             for(x=0;x<width;x++) {
893                 RGBA col = src[x];
894                 for(r=0;r<num;r++) {
895                     if(*(U32*)&col == *(U32*)&palette[r]) {
896                         dest[x] = r;
897                         break;
898                     }
899                 }
900                 if(r==num) {
901                     fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
902                             col.r, col.g, col.b, col.a, num);
903                     dest[x] = 0;
904                 }
905             }
906         }
907         swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
908         free(data2);
909         free(palette);
910     } else {
911         swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
912     }
913 }
914
915 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
916 {
917     int id, format, height, width, pos;
918     U32 datalen, datalen2;
919     int error;
920     int bpp = 1;
921     int cols = 0;
922     int pos2 = 0;
923     char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
924     int t, x, y;
925     RGBA *palette = 0;
926     U8 *data, *data2;
927     RGBA *dest;
928     if (tag->id != ST_DEFINEBITSLOSSLESS &&
929         tag->id != ST_DEFINEBITSLOSSLESS2) {
930         fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
931                 GET16(tag->data));
932         return 0;
933     }
934     swf_SetTagPos(tag, 0);
935     id = swf_GetU16(tag);
936     format = swf_GetU8(tag);
937     if (format == 3)
938         bpp = 8;
939     if (format == 4)
940         bpp = 16;
941     if (format == 5)
942         bpp = 32;
943     if (format != 3 && format != 5) {
944         if (format == 4)
945             fprintf(stderr,
946                     "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
947                     id);
948         else
949             fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
950                     format, id);
951         return 0;
952     }
953     *dwidth = width = swf_GetU16(tag);
954     *dheight = height = swf_GetU16(tag);
955
956     dest = rfx_alloc(sizeof(RGBA) * width * height);
957
958     if (format == 3)
959         cols = swf_GetU8(tag) + 1;
960     else
961         cols = 0;
962
963     data = 0;
964     datalen = (width * height * bpp / 8 + cols * 8);
965     do {
966         if (data)
967             rfx_free(data);
968         datalen += 4096;
969         data = rfx_alloc(datalen);
970         error =
971             uncompress(data, &datalen, &tag->data[tag->pos],
972                        tag->len - tag->pos);
973     } while (error == Z_BUF_ERROR);
974     if (error != Z_OK) {
975         fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
976         return 0;
977     }
978     pos = 0;
979
980     if (cols) {
981         palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
982         for (t = 0; t < cols; t++) {
983             palette[t].r = data[pos++];
984             palette[t].g = data[pos++];
985             palette[t].b = data[pos++];
986             if (alpha) {
987                 palette[t].a = data[pos++];
988             } else {
989                 palette[t].a = 255;
990             }
991         }
992     }
993
994     for (y = 0; y < height; y++) {
995         int srcwidth = width * (bpp / 8);
996         if (bpp == 32) {
997             if (!alpha) {
998                 // 32 bit to 24 bit "conversion"
999                 for (x = 0; x < width; x++) {
1000                     dest[pos2].r = data[pos + 1];
1001                     dest[pos2].g = data[pos + 2];
1002                     dest[pos2].b = data[pos + 3];
1003                     dest[pos2].a = 255;
1004                     pos2++;
1005                     pos += 4;   //ignore padding byte
1006                 }
1007             } else {
1008                 for (x = 0; x < width; x++) {
1009                     /* TODO: is un-premultiplying alpha the right thing to do?
1010                        dest[pos2].r = data[pos + 1];
1011                        dest[pos2].g = data[pos + 2];
1012                        dest[pos2].b = data[pos + 3];*/
1013                     int alpha = data[pos+0];
1014                     if(alpha) {
1015                         dest[pos2].r = ((int)data[pos + 1]*255)/alpha;
1016                         dest[pos2].g = ((int)data[pos + 2]*255)/alpha;
1017                         dest[pos2].b = ((int)data[pos + 3]*255)/alpha;
1018                     } else {
1019                         dest[pos2].r = data[pos + 1];
1020                         dest[pos2].g = data[pos + 2];
1021                         dest[pos2].b = data[pos + 3];
1022                     }
1023                     dest[pos2].a = data[pos + 0];       //alpha
1024                     pos2++;
1025                     pos += 4;
1026                 }
1027             }
1028         } else {
1029             for (x = 0; x < srcwidth; x++) {
1030                 dest[pos2] = palette[data[pos++]];
1031                 pos2++;
1032             }
1033         }
1034         pos += ((srcwidth + 3) & ~3) - srcwidth;        //align
1035     }
1036     if (palette)
1037         rfx_free(palette);
1038     rfx_free(data);
1039     return dest;
1040 }
1041
1042 #endif                          // HAVE_ZLIB
1043
1044 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1045 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1046 {
1047     JPEGBITS *jpeg;
1048     int y;
1049     int pos;
1050     int res = 0;
1051     U8 *data;
1052     z_stream zs;
1053
1054     pos = tag->len;
1055     swf_SetU32(tag, 0);         //placeholder
1056     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1057     for (y = 0; y < height; y++) {
1058         U8 scanline[3 * width];
1059         int x, p = 0;
1060         for (x = 0; x < width; x++) {
1061             scanline[p++] = bitmap[width * y + x].r;
1062             scanline[p++] = bitmap[width * y + x].g;
1063             scanline[p++] = bitmap[width * y + x].b;
1064         }
1065         swf_SetJPEGBitsLine(jpeg, scanline);
1066     }
1067     swf_SetJPEGBitsFinish(jpeg);
1068     PUT32(&tag->data[pos], tag->len - pos - 4);
1069
1070     data = rfx_alloc(OUTBUFFER_SIZE);
1071     memset(&zs, 0x00, sizeof(z_stream));
1072
1073     if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1074         fprintf(stderr, "rfxswf: zlib compression failed");
1075         return -3;
1076     }
1077
1078     zs.next_out = data;
1079     zs.avail_out = OUTBUFFER_SIZE;
1080
1081     for (y = 0; y < height; y++) {
1082         U8 scanline[width];
1083         int x, p = 0;
1084         for (x = 0; x < width; x++) {
1085             scanline[p++] = bitmap[width * y + x].a;
1086         }
1087         zs.avail_in = width;
1088         zs.next_in = scanline;
1089
1090         while (1) {
1091             if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1092                 fprintf(stderr, "rfxswf: zlib compression failed");
1093                 return -4;
1094             }
1095             if (zs.next_out != data) {
1096                 swf_SetBlock(tag, data, zs.next_out - data);
1097                 zs.next_out = data;
1098                 zs.avail_out = OUTBUFFER_SIZE;
1099             }
1100             if (!zs.avail_in) {
1101                 break;
1102             }
1103         }
1104     }
1105
1106     while (1) {
1107         int ret = deflate(&zs, Z_FINISH);
1108         if (ret != Z_OK && ret != Z_STREAM_END) {
1109             fprintf(stderr, "rfxswf: zlib compression failed");
1110             return -5;
1111         }
1112         if (zs.next_out != data) {
1113             swf_SetBlock(tag, data, zs.next_out - data);
1114             zs.next_out = data;
1115             zs.avail_out = OUTBUFFER_SIZE;
1116         }
1117         if (ret == Z_STREAM_END) {
1118             break;
1119         }
1120     }
1121
1122     deflateEnd(&zs);
1123     rfx_free(data);
1124     return 0;
1125 }
1126
1127 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1128 {
1129     TAG *tag1 = 0, *tag2 = 0;
1130     int has_alpha = swf_ImageHasAlpha(mem,width,height);
1131
1132     /* try lossless image */
1133     tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1134     swf_SetU16(tag1, bitid);
1135     swf_SetLosslessImage(tag1, mem, width, height);
1136
1137     /* try jpeg image */
1138     if(has_alpha) {
1139         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1140         swf_SetU16(tag2, bitid);
1141         swf_SetJPEGBits3(tag2, width, height, mem, quality);
1142     } else {
1143         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1144         swf_SetU16(tag2, bitid);
1145         swf_SetJPEGBits2(tag2, width, height, mem, quality);
1146     }
1147
1148     if(tag1 && tag1->len < tag2->len) {
1149         /* use the zlib version- it's smaller */
1150         tag1->prev = tag;
1151         if(tag) tag->next = tag1;
1152         tag = tag1;
1153         swf_DeleteTag(tag2);
1154     } else {
1155         /* use the jpeg version- it's smaller */
1156         tag2->prev = tag;
1157         if(tag) tag->next = tag2;
1158         tag = tag2;
1159         swf_DeleteTag(tag1);
1160     }
1161     return tag;
1162 }
1163
1164 #endif
1165
1166 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1167 {
1168     RGBA *img;
1169     
1170     swf_SetTagPos(tag, 2); // id is 2 bytes
1171
1172     if (tag->id == ST_DEFINEBITSJPEG ||
1173         tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1174 #ifdef HAVE_JPEGLIB
1175         return swf_JPEG2TagToImage(tag, dwidth, dheight);
1176 #else
1177         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1178         return 0;
1179 #endif
1180     }
1181     if (tag->id == ST_DEFINEBITSLOSSLESS ||
1182         tag->id == ST_DEFINEBITSLOSSLESS2) {
1183 #ifdef HAVE_ZLIB
1184         return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1185 #else
1186         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1187         return 0;
1188 #endif
1189     }
1190     fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1191             swf_TagGetName(tag));
1192     return 0;
1193 }
1194
1195 #undef OUTBUFFER_SIZE
1196
1197
1198 void swf_RemoveJPEGTables(SWF * swf)
1199 {
1200     TAG *tag = swf->firstTag;
1201     TAG *tables_tag = 0;
1202     while (tag) {
1203         if (tag->id == ST_JPEGTABLES) {
1204             tables_tag = tag;
1205         }
1206         tag = tag->next;
1207     }
1208
1209     if (!tables_tag)
1210         return;
1211
1212     tag = swf->firstTag;
1213     while (tag) {
1214         if (tag->id == ST_DEFINEBITSJPEG) {
1215             int len = tag->len;
1216             void *data = rfx_alloc(len);
1217             swf_GetBlock(tag, data, tag->len);
1218             swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1219             swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1220             swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1221             swf_SetBlock(tag, &((U8*)data)[2], len-2);
1222             free(data);
1223         }
1224         tag = tag->next;
1225     }
1226     if (swf->firstTag == tables_tag)
1227         swf->firstTag = tables_tag->next;
1228     swf_DeleteTag(tables_tag);
1229 }
1230
1231 typedef struct scale_lookup {
1232     int pos;
1233     unsigned int weight;
1234 } scale_lookup_t;
1235
1236 typedef struct rgba_int {
1237     unsigned int r,g,b,a;
1238 } rgba_int_t;
1239
1240 static int bicubic = 0;
1241
1242 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1243 {
1244     scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1245     scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1246     double fx = ((double)width)/((double)newwidth);
1247     double px = 0;
1248     int x;
1249     scale_lookup_t*p_x = lookupx;
1250
1251     if(newwidth<=width) {
1252         for(x=0;x<newwidth;x++) {
1253             double ex = px + fx;
1254             int fromx = (int)px;
1255             int tox = (int)ex;
1256             double rem = fromx+1-px;
1257             int i = (int)(256/fx);
1258             int xweight = (int)(rem*256/fx);
1259             int xx;
1260             int w = 0;
1261             lblockx[x] = p_x;
1262             if(tox>=width) tox = width-1;
1263             for(xx=fromx;xx<=tox;xx++) {
1264                 if(xx==fromx && xx==tox) p_x->weight = 256;
1265                 else if(xx==fromx) p_x->weight = xweight;
1266                 else if(xx==tox) p_x->weight = 256-w;
1267                 else p_x->weight = i;
1268                 w+=p_x->weight;
1269                 p_x->pos = xx;
1270                 p_x++;
1271             }
1272             px = ex;
1273         }
1274     } else {
1275         for(x=0;x<newwidth;x++) {
1276             int ix1 = (int)px;
1277             int ix2 = ((int)px)+1;
1278             double r = px-ix1;
1279             if(ix2>=width) ix2=width-1;
1280             lblockx[x] = p_x;
1281             if(bicubic)
1282                 r = -2*r*r*r+3*r*r;
1283             p_x[0].weight = (int)(256*(1-r));
1284             p_x[0].pos = ix1;
1285             p_x[1].weight = 256-p_x[0].weight;
1286             p_x[1].pos = ix2;
1287             p_x+=2;
1288             px += fx;
1289         }
1290     }
1291     lblockx[newwidth] = p_x;
1292     return lblockx;
1293 }
1294
1295 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1296 {
1297     int t;
1298     int len = width*height;
1299
1300     U32* img = (U32*)data;
1301     U32 color1 = img[0];
1302     U32 color2 = 0;
1303     for(t=1;t<len;t++) {
1304         if(img[t] != color1) {
1305             color2 = img[t];
1306             break;
1307         }
1308     }
1309     *(U32*)&colors[0] = color1;
1310     *(U32*)&colors[1] = color2;
1311     for(t=0;t<len;t++) {
1312         if(img[t] == color1) {
1313             img[t] = 0;
1314         } else {
1315             img[t] = 0xffffffff;
1316         }
1317     }
1318 }
1319
1320 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1321 {
1322     int t;
1323     int len = width*height;
1324
1325     for(t=0;t<len;t++) {
1326         U32 m = data[t].r;
1327         data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1328         data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1329         data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1330         data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1331     }
1332 }
1333
1334 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1335 {
1336     int x,y;
1337     RGBA* newdata; 
1338     scale_lookup_t *p, **lblockx,**lblocky;
1339     rgba_int_t*tmpline;
1340     int monochrome = 0;
1341     RGBA monochrome_colors[2];
1342     
1343     if(newwidth<1 || newheight<1)
1344         return 0;
1345
1346     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1347         monochrome=1;
1348         encodeMonochromeImage(data, width, height, monochrome_colors);
1349     }
1350
1351     tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1352     newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1353   
1354     lblockx = make_scale_lookup(width, newwidth);
1355     lblocky = make_scale_lookup(height, newheight);
1356
1357     for(p=lblocky[0];p<lblocky[newheight];p++)
1358         p->pos*=width;
1359
1360     for(y=0;y<newheight;y++) {
1361         RGBA*destline = &newdata[y*newwidth];
1362         
1363         /* create lookup table for y */
1364         rgba_int_t*l = tmpline;
1365         scale_lookup_t*p_y,*p_x;
1366         memset(tmpline, 0, width*sizeof(rgba_int_t));
1367         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1368             RGBA*line = &data[p_y->pos];
1369             scale_lookup_t*p_x;
1370             int weight = p_y->weight;
1371             for(x=0;x<width;x++) {
1372                 tmpline[x].r += line[x].r*weight;
1373                 tmpline[x].g += line[x].g*weight;
1374                 tmpline[x].b += line[x].b*weight;
1375                 tmpline[x].a += line[x].a*weight;
1376             }
1377         }
1378
1379         /* process x direction */
1380         p_x = lblockx[0];
1381         for(x=0;x<newwidth;x++) {
1382             unsigned int r=0,g=0,b=0,a=0;
1383             scale_lookup_t*p_x_to = lblockx[x+1];
1384             do { 
1385                 rgba_int_t* col = &tmpline[p_x->pos];
1386                 unsigned int weight = p_x->weight;
1387                 r += col->r*weight;
1388                 g += col->g*weight;
1389                 b += col->b*weight;
1390                 a += col->a*weight;
1391                 p_x++;
1392             } while (p_x<p_x_to);
1393
1394             destline->r = r >> 16;
1395             destline->g = g >> 16;
1396             destline->b = b >> 16;
1397             destline->a = a >> 16;
1398            
1399             destline++;
1400         }
1401     }
1402
1403     if(monochrome)
1404         decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);
1405
1406     free(tmpline);
1407     free(*lblockx);
1408     free(lblockx);
1409     free(*lblocky);
1410     free(lblocky);
1411     return newdata;
1412 }
1413
1414