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