a02483566eeaa51e2000292f218256fe6a3923cf
[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     rfx_free(scanline);
397     swf_SetJPEGBitsFinish(out);
398     jpeg_finish_decompress(&cinfo);
399     fclose(f);
400
401     return 0;
402 }
403
404 typedef struct _JPEGFILEMGR {
405     struct jpeg_destination_mgr mgr;
406     JOCTET *buffer;
407     struct jpeg_compress_struct* cinfo;
408     struct jpeg_error_mgr* jerr;
409     FILE*fi;
410 } JPEGFILEMGR;
411
412 static void file_init_destination(j_compress_ptr cinfo) 
413
414     JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
415     struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
416
417     fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
418     if(!fmgr->buffer) {
419         perror("malloc");
420         fprintf(stderr, "Out of memory!\n");
421         exit(1);
422     }
423
424     dmgr->next_output_byte = fmgr->buffer;
425     dmgr->free_in_buffer = OUTBUFFER_SIZE;
426 }
427
428 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
429
430     JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
431     struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
432
433     if(fmgr->fi)
434         fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
435
436     dmgr->next_output_byte = fmgr->buffer;
437     dmgr->free_in_buffer = OUTBUFFER_SIZE;
438     return 1;
439 }
440
441 static void file_term_destination(j_compress_ptr cinfo) 
442
443     JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
444     struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
445
446     if(fmgr->fi)
447         fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
448
449     rfx_free(fmgr->buffer);
450     fmgr->buffer = 0;
451     dmgr->free_in_buffer = 0;
452     dmgr->next_output_byte = 0;
453 }
454
455 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
456 {
457     JPEGFILEMGR fmgr;
458     struct jpeg_compress_struct cinfo;
459     struct jpeg_error_mgr jerr;
460     unsigned char*data2 = 0;
461     int y;
462
463     FILE*fi = fopen(filename, "wb");
464     if(!fi) {
465         char buf[256];
466         sprintf(buf, "rfxswf: Couldn't create %s", filename);
467         perror(buf);
468         return;
469     }
470     data2 = rfx_calloc(width*3);
471
472     memset(&cinfo, 0, sizeof(cinfo));
473     memset(&jerr, 0, sizeof(jerr));
474     memset(&fmgr, 0, sizeof(fmgr));
475     cinfo.err = jpeg_std_error(&jerr);
476     jpeg_create_compress(&cinfo);
477
478     fmgr.mgr.init_destination = file_init_destination;
479     fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
480     fmgr.mgr.term_destination = file_term_destination;
481     fmgr.fi = fi;
482     fmgr.cinfo = &cinfo;
483     fmgr.jerr = &jerr;
484     cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
485
486     // init compression
487
488     cinfo.image_width  = width;
489     cinfo.image_height = height;
490     cinfo.input_components = 3;
491     cinfo.in_color_space = JCS_RGB;
492     jpeg_set_defaults(&cinfo);
493     cinfo.dct_method = JDCT_IFAST;
494     jpeg_set_quality(&cinfo,quality,TRUE);
495
496     //jpeg_write_tables(&cinfo);
497     //jpeg_suppress_tables(&cinfo, TRUE);
498     jpeg_start_compress(&cinfo, FALSE);
499
500     for(y=0;y<height;y++) {
501         int x;
502         RGBA*src = &pixels[y*width];
503         for(x=0;x<width;x++) {
504             data2[x*3+0] = src[x].r;
505             data2[x*3+1] = src[x].g;
506             data2[x*3+2] = src[x].b;
507         }
508         jpeg_write_scanlines(&cinfo, &data2, 1);
509     }
510     rfx_free(data2);
511     jpeg_finish_compress(&cinfo);
512     jpeg_destroy_compress(&cinfo);
513
514     fclose(fi);
515 }
516
517 /*  jpeg_source_mgr functions */
518 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
519 {
520     TAG *tag = (TAG *) cinfo->client_data;
521     if (tag->id == ST_DEFINEBITSJPEG3) {
522         swf_SetTagPos(tag, 6);
523     } else {
524         swf_SetTagPos(tag, 2);
525     }
526     cinfo->src->bytes_in_buffer = 0;
527 }
528 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
529 {
530     TAG *tag = (TAG *) cinfo->client_data;
531     if (tag->data[tag->pos + 0] == 0xff &&
532         tag->data[tag->pos + 1] == 0xd9 &&
533         tag->data[tag->pos + 2] == 0xff &&
534         tag->data[tag->pos + 3] == 0xd8) {
535         tag->pos += 4;
536     }
537     if (tag->pos >= tag->len) {
538         cinfo->src->next_input_byte = 0;
539         cinfo->src->bytes_in_buffer = 0;
540         return 0;
541     }
542     cinfo->src->next_input_byte = &tag->data[tag->pos];
543     cinfo->src->bytes_in_buffer = 1;    //tag->len - tag->pos;
544     tag->pos += 1;
545     return 1;
546 }
547 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
548 {
549     TAG *tag = (TAG *) cinfo->client_data;
550     cinfo->src->next_input_byte = 0;
551     cinfo->src->bytes_in_buffer = 0;
552     tag->pos += count;
553 }
554 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
555 {
556     return jpeg_resync_to_restart(cinfo, desired);
557 }
558 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
559 {
560     TAG *tag = (TAG *) cinfo->client_data;
561 }
562 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
563 {
564     struct jpeg_decompress_struct cinfo;
565     struct jpeg_error_mgr jerr;
566     struct jpeg_source_mgr mgr;
567     RGBA *dest;
568     int y;
569     int offset = 0;
570     int oldtaglen = 0;
571     *width = 0;
572     *height = 0;
573
574     if (tag->id == ST_DEFINEBITSJPEG) {
575         fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
576         return 0;
577     }
578     if (tag->id == ST_DEFINEBITSJPEG3) {
579 #ifdef HAVE_ZLIB
580         offset = swf_GetU32(tag);
581         oldtaglen = tag->len;
582         tag->len = offset+6;
583 #else
584         fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
585         return 0;
586 #endif
587     }
588
589     cinfo.err = jpeg_std_error(&jerr);
590     jpeg_create_decompress(&cinfo);
591
592     cinfo.client_data = (void *) tag;
593     cinfo.src = &mgr;
594     cinfo.src->init_source = tag_init_source;
595     cinfo.src->fill_input_buffer = tag_fill_input_buffer;
596     cinfo.src->skip_input_data = tag_skip_input_data;
597     cinfo.src->resync_to_restart = jpeg_resync_to_restart;
598     cinfo.src->term_source = tag_term_source;
599     cinfo.out_color_space = JCS_RGB;
600
601     jpeg_read_header(&cinfo, TRUE);
602     *width = cinfo.image_width;
603     *height = cinfo.image_height;
604     dest =
605         rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
606
607     jpeg_start_decompress(&cinfo);
608     for (y = 0; y < cinfo.output_height; y++) {
609         RGBA *line = &dest[y * cinfo.image_width];
610         U8 *to = (U8 *) line;
611         int x;
612         jpeg_read_scanlines(&cinfo, &to, 1);
613         for (x = cinfo.output_width - 1; x >= 0; --x) {
614             int r = to[x * 3 + 0];
615             int g = to[x * 3 + 1];
616             int b = to[x * 3 + 2];
617             line[x].r = r;
618             line[x].g = g;
619             line[x].b = b;
620             line[x].a = 255;
621         }
622     }
623
624     jpeg_finish_decompress(&cinfo);
625
626     jpeg_destroy_decompress(&cinfo);
627
628 #ifdef HAVE_ZLIB
629     if(offset) {
630         uLongf datalen = cinfo.output_width*cinfo.output_height;
631         U8* alphadata = (U8*)rfx_alloc(datalen);
632         int error;
633         tag->len = oldtaglen;
634         swf_SetTagPos(tag, 6+offset);
635         error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
636         if (error != Z_OK) {
637             fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
638             return 0;
639         }
640         for(y=0;y<cinfo.output_height;y++) {
641             RGBA*line = &dest[y*cinfo.output_width];
642             U8*aline = &alphadata[y*cinfo.output_width];
643             int x;
644             for(x=0;x<cinfo.output_width;x++) {
645                 line[x].a = aline[x];
646             }
647         }
648         free(alphadata);
649     }
650 #endif
651     return dest;
652 }
653
654 #endif                          // HAVE_JPEGLIB
655
656 // Lossless compression texture based on zlib
657
658 #ifdef HAVE_ZLIB
659
660 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
661 {
662     U8 *data = rfx_alloc(OUTBUFFER_SIZE);
663     zs->next_out = data;
664     zs->avail_out = OUTBUFFER_SIZE;
665     while (1) {
666         int status = deflate(zs, Z_NO_FLUSH);
667
668         if (status != Z_OK) {
669             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
670             rfx_free(data);
671             return status;
672         }
673
674         if (zs->next_out != data) {
675             swf_SetBlock(t, data, zs->next_out - data);
676             zs->next_out = data;
677             zs->avail_out = OUTBUFFER_SIZE;
678         }
679
680         if (zs->avail_in == 0)
681             break;
682     }
683
684     if (!finish) {
685         rfx_free(data);
686         return 0;
687     }
688
689     while (1) {
690         int status = deflate(zs, Z_FINISH);
691         if (status != Z_OK && status != Z_STREAM_END) {
692             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
693             rfx_free(data);
694             return status;
695         }
696
697         if (zs->next_out != data) {
698             swf_SetBlock(t, data, zs->next_out - data);
699             zs->next_out = data;
700             zs->avail_out = OUTBUFFER_SIZE;
701         }
702
703         if (status == Z_STREAM_END)
704             break;
705     }
706     rfx_free(data);
707     return 0;
708 }
709
710
711 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
712 {
713     int res = 0;
714     int bps;
715
716     switch (bitmap_flags) {
717     case BMF_8BIT:
718         return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
719     case BMF_16BIT:
720         bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
721         break;
722     case BMF_32BIT:
723         bps = width * 4;
724         break;
725     default:
726         fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
727         return -1;
728     }
729
730     swf_SetU8(t, bitmap_flags);
731     swf_SetU16(t, width);
732     swf_SetU16(t, height);
733
734     {
735         z_stream zs;
736
737         memset(&zs, 0x00, sizeof(z_stream));
738         zs.zalloc = Z_NULL;
739         zs.zfree = Z_NULL;
740
741         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
742             zs.avail_in = bps * height;
743             zs.next_in = bitmap;
744
745             if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
746                 res = -3;
747             deflateEnd(&zs);
748
749         } else
750             res = -3;           // zlib error
751     }
752     return res;
753 }
754
755 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
756 {
757     RGBA *pal = palette;
758     int bps = BYTES_PER_SCANLINE(width);
759     int res = 0;
760
761     if (!pal)                   // create default palette for grayscale images
762     {
763         int i;
764         pal = rfx_alloc(256 * sizeof(RGBA));
765         for (i = 0; i < 256; i++) {
766             pal[i].r = pal[i].g = pal[i].b = i;
767             pal[i].a = 0xff;
768         }
769         ncolors = 256;
770     }
771
772     if ((ncolors < 2) || (ncolors > 256) || (!t)) {
773         fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
774                 ncolors);
775         return -1;              // parameter error
776     }
777
778     swf_SetU8(t, BMF_8BIT);
779     swf_SetU16(t, width);
780     swf_SetU16(t, height);
781     swf_SetU8(t, ncolors - 1);  // number of pal entries
782
783     {
784         z_stream zs;
785
786         memset(&zs, 0x00, sizeof(z_stream));
787         zs.zalloc = Z_NULL;
788         zs.zfree = Z_NULL;
789
790         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
791             U8 *zpal;           // compress palette
792             if ((zpal = rfx_alloc(ncolors * 4))) {
793                 U8 *pp = zpal;
794                 int i;
795
796                 /* be careful with ST_DEFINEBITSLOSSLESS2, because
797                    the Flash player produces great bugs if you use too many
798                    alpha colors in your palette. The only sensible result that
799                    can be archeived is setting one color to r=0,b=0,g=0,a=0 to
800                    make transparent parts in sprites. That's the cause why alpha
801                    handling is implemented in lossless routines of rfxswf.
802
803                    Indeed: I haven't understood yet how flash player handles
804                    alpha values different from 0 and 0xff in lossless bitmaps...
805                  */
806
807                 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2)  // have alpha channel?
808                 {
809                     for (i = 0; i < ncolors; i++) {
810                         pp[0] = pal[i].r;
811                         pp[1] = pal[i].g;
812                         pp[2] = pal[i].b;
813                         pp[3] = pal[i].a;
814                         pp += 4;
815                     }
816                     zs.avail_in = 4 * ncolors;
817                 } else {
818                     for (i = 0; i < ncolors; i++)       // pack RGBA structures to RGB 
819                     {
820                         pp[0] = pal[i].r;
821                         pp[1] = pal[i].g;
822                         pp[2] = pal[i].b;
823                         pp += 3;
824                     }
825                     zs.avail_in = 3 * ncolors;
826                 }
827
828                 zs.next_in = zpal;
829
830                 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
831                     res = -3;
832
833                 // compress bitmap
834                 zs.next_in = bitmap;
835                 zs.avail_in = (bps * height * sizeof(U8));
836
837                 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
838                     res = -3;
839
840                 deflateEnd(&zs);
841
842                 rfx_free(zpal);
843             } else
844                 res = -2;       // memory error
845         } else
846             res = -3;           // zlib error
847     }
848
849     if (!palette)
850         rfx_free(pal);
851
852     return res;
853 }
854
855 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
856 {
857     return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
858 }
859
860 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
861 {
862     int num = width*height;
863     int t;
864     for(t=0;t<num;t++) {
865         data[t].r = ((int)data[t].r*data[t].a)/255;
866         data[t].g = ((int)data[t].g*data[t].a)/255;
867         data[t].b = ((int)data[t].b*data[t].a)/255;
868     }
869 }
870
871 /* expects mem to be non-premultiplied */
872 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
873 {
874     int hasalpha = swf_ImageHasAlpha(data, width, height);
875     int num;
876     if(!hasalpha) {
877         tag->id = ST_DEFINEBITSLOSSLESS;
878     } else {
879         tag->id = ST_DEFINEBITSLOSSLESS2;
880         swf_PreMultiplyAlpha(data, width, height);
881     }
882     num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
883     if(num>1 && num<=256) {
884         RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
885         int width2 = BYTES_PER_SCANLINE(width);
886         U8*data2 = (U8*)malloc(width2*height);
887         int len = width*height;
888         int x,y;
889         int r;
890         swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
891         for(y=0;y<height;y++) {
892             RGBA*src = &data[width*y];
893             U8*dest = &data2[width2*y];
894             for(x=0;x<width;x++) {
895                 RGBA col = src[x];
896                 for(r=0;r<num;r++) {
897                     if(*(U32*)&col == *(U32*)&palette[r]) {
898                         dest[x] = r;
899                         break;
900                     }
901                 }
902                 if(r==num) {
903                     fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
904                             col.r, col.g, col.b, col.a, num);
905                     dest[x] = 0;
906                 }
907             }
908         }
909         swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
910         free(data2);
911         free(palette);
912     } else {
913         swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
914     }
915 }
916
917 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
918 {
919     int id, format, height, width, pos;
920     uLongf datalen, datalen2;
921     int error;
922     int bpp = 1;
923     int cols = 0;
924     int pos2 = 0;
925     char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
926     int t, x, y;
927     RGBA *palette = 0;
928     U8 *data, *data2;
929     RGBA *dest;
930     if (tag->id != ST_DEFINEBITSLOSSLESS &&
931         tag->id != ST_DEFINEBITSLOSSLESS2) {
932         fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
933                 GET16(tag->data));
934         return 0;
935     }
936     swf_SetTagPos(tag, 0);
937     id = swf_GetU16(tag);
938     format = swf_GetU8(tag);
939     if (format == 3)
940         bpp = 8;
941     if (format == 4)
942         bpp = 16;
943     if (format == 5)
944         bpp = 32;
945     if (format != 3 && format != 5) {
946         if (format == 4)
947             fprintf(stderr,
948                     "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
949                     id);
950         else
951             fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
952                     format, id);
953         return 0;
954     }
955     *dwidth = width = swf_GetU16(tag);
956     *dheight = height = swf_GetU16(tag);
957
958     dest = rfx_alloc(sizeof(RGBA) * width * height);
959
960     if (format == 3)
961         cols = swf_GetU8(tag) + 1;
962     else
963         cols = 0;
964
965     data = 0;
966     datalen = (width * height * bpp / 8 + cols * 8);
967     do {
968         if (data)
969             rfx_free(data);
970         datalen += 4096;
971         data = rfx_alloc(datalen);
972         error =
973             uncompress(data, &datalen, &tag->data[tag->pos],
974                        tag->len - tag->pos);
975     } while (error == Z_BUF_ERROR);
976     if (error != Z_OK) {
977         fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
978         return 0;
979     }
980     pos = 0;
981
982     if (cols) {
983         palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
984         for (t = 0; t < cols; t++) {
985             palette[t].r = data[pos++];
986             palette[t].g = data[pos++];
987             palette[t].b = data[pos++];
988             if (alpha) {
989                 palette[t].a = data[pos++];
990             } else {
991                 palette[t].a = 255;
992             }
993         }
994     }
995
996     for (y = 0; y < height; y++) {
997         int srcwidth = width * (bpp / 8);
998         if (bpp == 32) {
999             if (!alpha) {
1000                 // 32 bit to 24 bit "conversion"
1001                 for (x = 0; x < width; x++) {
1002                     dest[pos2].r = data[pos + 1];
1003                     dest[pos2].g = data[pos + 2];
1004                     dest[pos2].b = data[pos + 3];
1005                     dest[pos2].a = 255;
1006                     pos2++;
1007                     pos += 4;   //ignore padding byte
1008                 }
1009             } else {
1010                 for (x = 0; x < width; x++) {
1011                     /* remove premultiplication */
1012                     int alpha = data[pos+0];
1013                     if(alpha)
1014                         alpha = 0xff0000/alpha;
1015                     dest[pos2].r = (data[pos + 1]*alpha)>>16;
1016                     dest[pos2].g = (data[pos + 2]*alpha)>>16;
1017                     dest[pos2].b = (data[pos + 3]*alpha)>>16;
1018                     dest[pos2].a = data[pos + 0];       //alpha
1019                     pos2++;
1020                     pos += 4;
1021                 }
1022             }
1023         } else {
1024             for (x = 0; x < srcwidth; x++) {
1025                 dest[pos2] = palette[data[pos++]];
1026                 pos2++;
1027             }
1028         }
1029         pos += ((srcwidth + 3) & ~3) - srcwidth;        //align
1030     }
1031     if (palette)
1032         rfx_free(palette);
1033     rfx_free(data);
1034     return dest;
1035 }
1036
1037 #endif                          // HAVE_ZLIB
1038
1039 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1040
1041 /* expects bitmap to be non-premultiplied */
1042 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1043 {
1044     JPEGBITS *jpeg;
1045     int y;
1046     int pos;
1047     int res = 0;
1048     U8 *data;
1049     z_stream zs;
1050
1051     pos = tag->len;
1052     swf_SetU32(tag, 0);         //placeholder
1053     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1054     for (y = 0; y < height; y++) {
1055         U8 scanline[3 * width];
1056         int x, p = 0;
1057         for (x = 0; x < width; x++) {
1058             //int ia = bitmap[width*y+x].a;
1059             //if(ia) {
1060             //    /* remove premultiplication */
1061             //    ia = 0xff0000/ia;
1062             //}
1063             //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1064             //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1065             //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1066             scanline[p++] = bitmap[width * y + x].r;
1067             scanline[p++] = bitmap[width * y + x].g;
1068             scanline[p++] = bitmap[width * y + x].b;
1069         }
1070         swf_SetJPEGBitsLine(jpeg, scanline);
1071     }
1072     swf_SetJPEGBitsFinish(jpeg);
1073     PUT32(&tag->data[pos], tag->len - pos - 4);
1074
1075     data = rfx_alloc(OUTBUFFER_SIZE);
1076     memset(&zs, 0x00, sizeof(z_stream));
1077
1078     if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1079         fprintf(stderr, "rfxswf: zlib compression failed");
1080         return -3;
1081     }
1082
1083     zs.next_out = data;
1084     zs.avail_out = OUTBUFFER_SIZE;
1085
1086     for (y = 0; y < height; y++) {
1087         U8 scanline[width];
1088         int x, p = 0;
1089         for (x = 0; x < width; x++) {
1090             scanline[p++] = bitmap[width * y + x].a;
1091         }
1092         zs.avail_in = width;
1093         zs.next_in = scanline;
1094
1095         while (1) {
1096             if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1097                 fprintf(stderr, "rfxswf: zlib compression failed");
1098                 return -4;
1099             }
1100             if (zs.next_out != data) {
1101                 swf_SetBlock(tag, data, zs.next_out - data);
1102                 zs.next_out = data;
1103                 zs.avail_out = OUTBUFFER_SIZE;
1104             }
1105             if (!zs.avail_in) {
1106                 break;
1107             }
1108         }
1109     }
1110
1111     while (1) {
1112         int ret = deflate(&zs, Z_FINISH);
1113         if (ret != Z_OK && ret != Z_STREAM_END) {
1114             fprintf(stderr, "rfxswf: zlib compression failed");
1115             return -5;
1116         }
1117         if (zs.next_out != data) {
1118             swf_SetBlock(tag, data, zs.next_out - data);
1119             zs.next_out = data;
1120             zs.avail_out = OUTBUFFER_SIZE;
1121         }
1122         if (ret == Z_STREAM_END) {
1123             break;
1124         }
1125     }
1126
1127     deflateEnd(&zs);
1128     rfx_free(data);
1129     return 0;
1130 }
1131
1132 /* expects mem to be non-premultiplied */
1133 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1134 {
1135     TAG *tag1 = 0, *tag2 = 0;
1136     int has_alpha = swf_ImageHasAlpha(mem,width,height);
1137
1138     /* try lossless image */
1139     tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1140     swf_SetU16(tag1, bitid);
1141     swf_SetLosslessImage(tag1, mem, width, height);
1142
1143     /* try jpeg image */
1144     if(has_alpha) {
1145         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1146         swf_SetU16(tag2, bitid);
1147         swf_SetJPEGBits3(tag2, width, height, mem, quality);
1148     } else {
1149         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1150         swf_SetU16(tag2, bitid);
1151         swf_SetJPEGBits2(tag2, width, height, mem, quality);
1152     }
1153
1154     if(quality>100 || (tag1 && tag1->len < tag2->len)) {
1155         /* use the zlib version- it's smaller */
1156         tag1->prev = tag;
1157         if(tag) tag->next = tag1;
1158         tag = tag1;
1159         swf_DeleteTag(tag2);
1160     } else {
1161         /* use the jpeg version- it's smaller */
1162         tag2->prev = tag;
1163         if(tag) tag->next = tag2;
1164         tag = tag2;
1165         swf_DeleteTag(tag1);
1166     }
1167     return tag;
1168 }
1169
1170 #endif
1171
1172 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1173 {
1174     RGBA *img;
1175     
1176     swf_SetTagPos(tag, 2); // id is 2 bytes
1177
1178     if (tag->id == ST_DEFINEBITSJPEG ||
1179         tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1180 #ifdef HAVE_JPEGLIB
1181         return swf_JPEG2TagToImage(tag, dwidth, dheight);
1182 #else
1183         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1184         return 0;
1185 #endif
1186     }
1187     if (tag->id == ST_DEFINEBITSLOSSLESS ||
1188         tag->id == ST_DEFINEBITSLOSSLESS2) {
1189 #ifdef HAVE_ZLIB
1190         return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1191 #else
1192         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1193         return 0;
1194 #endif
1195     }
1196     fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1197             swf_TagGetName(tag));
1198     return 0;
1199 }
1200
1201 #undef OUTBUFFER_SIZE
1202
1203
1204 void swf_RemoveJPEGTables(SWF * swf)
1205 {
1206     TAG *tag = swf->firstTag;
1207     TAG *tables_tag = 0;
1208     while (tag) {
1209         if (tag->id == ST_JPEGTABLES) {
1210             tables_tag = tag;
1211         }
1212         tag = tag->next;
1213     }
1214
1215     if (!tables_tag)
1216         return;
1217
1218     tag = swf->firstTag;
1219     while (tag) {
1220         if (tag->id == ST_DEFINEBITSJPEG) {
1221             int len = tag->len;
1222             void *data = rfx_alloc(len);
1223             swf_GetBlock(tag, data, tag->len);
1224             swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1225             swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1226             swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1227             swf_SetBlock(tag, &((U8*)data)[2], len-2);
1228             free(data);
1229         }
1230         tag = tag->next;
1231     }
1232     if (swf->firstTag == tables_tag)
1233         swf->firstTag = tables_tag->next;
1234     swf_DeleteTag(tables_tag);
1235 }
1236
1237 typedef struct scale_lookup {
1238     int pos;
1239     unsigned int weight;
1240 } scale_lookup_t;
1241
1242 typedef struct rgba_int {
1243     unsigned int r,g,b,a;
1244 } rgba_int_t;
1245
1246 static int bicubic = 0;
1247
1248 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1249 {
1250     scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1251     scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1252     double fx = ((double)width)/((double)newwidth);
1253     double px = 0;
1254     int x;
1255     scale_lookup_t*p_x = lookupx;
1256
1257     if(newwidth<=width) {
1258         for(x=0;x<newwidth;x++) {
1259             double ex = px + fx;
1260             int fromx = (int)px;
1261             int tox = (int)ex;
1262             double rem = fromx+1-px;
1263             int i = (int)(256/fx);
1264             int xweight = (int)(rem*256/fx);
1265             int xx;
1266             int w = 0;
1267             lblockx[x] = p_x;
1268             if(tox>=width) tox = width-1;
1269             for(xx=fromx;xx<=tox;xx++) {
1270                 if(xx==fromx && xx==tox) p_x->weight = 256;
1271                 else if(xx==fromx) p_x->weight = xweight;
1272                 else if(xx==tox) p_x->weight = 256-w;
1273                 else p_x->weight = i;
1274                 w+=p_x->weight;
1275                 p_x->pos = xx;
1276                 p_x++;
1277             }
1278             px = ex;
1279         }
1280     } else {
1281         for(x=0;x<newwidth;x++) {
1282             int ix1 = (int)px;
1283             int ix2 = ((int)px)+1;
1284             double r = px-ix1;
1285             if(ix2>=width) ix2=width-1;
1286             lblockx[x] = p_x;
1287             if(bicubic)
1288                 r = -2*r*r*r+3*r*r;
1289             p_x[0].weight = (int)(256*(1-r));
1290             p_x[0].pos = ix1;
1291             p_x[1].weight = 256-p_x[0].weight;
1292             p_x[1].pos = ix2;
1293             p_x+=2;
1294             px += fx;
1295         }
1296     }
1297     lblockx[newwidth] = p_x;
1298     return lblockx;
1299 }
1300
1301 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1302 {
1303     int t;
1304     int len = width*height;
1305
1306     U32* img = (U32*)data;
1307     U32 color1 = img[0];
1308     U32 color2 = 0;
1309     for(t=1;t<len;t++) {
1310         if(img[t] != color1) {
1311             color2 = img[t];
1312             break;
1313         }
1314     }
1315     *(U32*)&colors[0] = color1;
1316     *(U32*)&colors[1] = color2;
1317     for(t=0;t<len;t++) {
1318         if(img[t] == color1) {
1319             img[t] = 0;
1320         } else {
1321             img[t] = 0xffffffff;
1322         }
1323     }
1324 }
1325
1326 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1327 {
1328     int t;
1329     int len = width*height;
1330
1331     for(t=0;t<len;t++) {
1332         U32 m = data[t].r;
1333         data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1334         data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1335         data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1336         data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1337     }
1338 }
1339
1340 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1341 {
1342     int x,y;
1343     RGBA* newdata; 
1344     scale_lookup_t *p, **lblockx,**lblocky;
1345     rgba_int_t*tmpline;
1346     int monochrome = 0;
1347     RGBA monochrome_colors[2];
1348     
1349     if(newwidth<1 || newheight<1)
1350         return 0;
1351
1352     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1353         monochrome=1;
1354         encodeMonochromeImage(data, width, height, monochrome_colors);
1355     }
1356
1357     tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1358     newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1359   
1360     lblockx = make_scale_lookup(width, newwidth);
1361     lblocky = make_scale_lookup(height, newheight);
1362
1363     for(p=lblocky[0];p<lblocky[newheight];p++)
1364         p->pos*=width;
1365
1366     for(y=0;y<newheight;y++) {
1367         RGBA*destline = &newdata[y*newwidth];
1368         
1369         /* create lookup table for y */
1370         rgba_int_t*l = tmpline;
1371         scale_lookup_t*p_y,*p_x;
1372         memset(tmpline, 0, width*sizeof(rgba_int_t));
1373         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1374             RGBA*line = &data[p_y->pos];
1375             scale_lookup_t*p_x;
1376             int weight = p_y->weight;
1377             for(x=0;x<width;x++) {
1378                 tmpline[x].r += line[x].r*weight;
1379                 tmpline[x].g += line[x].g*weight;
1380                 tmpline[x].b += line[x].b*weight;
1381                 tmpline[x].a += line[x].a*weight;
1382             }
1383         }
1384
1385         /* process x direction */
1386         p_x = lblockx[0];
1387         for(x=0;x<newwidth;x++) {
1388             unsigned int r=0,g=0,b=0,a=0;
1389             scale_lookup_t*p_x_to = lblockx[x+1];
1390             do { 
1391                 rgba_int_t* col = &tmpline[p_x->pos];
1392                 unsigned int weight = p_x->weight;
1393                 r += col->r*weight;
1394                 g += col->g*weight;
1395                 b += col->b*weight;
1396                 a += col->a*weight;
1397                 p_x++;
1398             } while (p_x<p_x_to);
1399
1400             destline->r = r >> 16;
1401             destline->g = g >> 16;
1402             destline->b = b >> 16;
1403             destline->a = a >> 16;
1404            
1405             destline++;
1406         }
1407     }
1408
1409     if(monochrome)
1410         decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);
1411
1412     free(tmpline);
1413     free(*lblockx);
1414     free(lblockx);
1415     free(*lblocky);
1416     free(lblocky);
1417     return newdata;
1418 }
1419
1420