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