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