4fa38f55c0eb1d5904e16f061a35a546e3c09fe7
[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     tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1186     swf_SetU16(tag1, bitid);
1187     swf_SetLosslessImage(tag1, mem, width, height);
1188
1189 #if defined(HAVE_JPEGLIB)
1190     /* try jpeg image */
1191     if(has_alpha) {
1192         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1193         swf_SetU16(tag2, bitid);
1194         swf_SetJPEGBits3(tag2, width, height, mem, quality);
1195     } else {
1196         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1197         swf_SetU16(tag2, bitid);
1198         swf_SetJPEGBits2(tag2, width, height, mem, quality);
1199     }
1200 #endif
1201
1202     if(quality>100 || !tag2 || (tag1 && tag1->len < tag2->len)) {
1203         /* use the zlib version- it's smaller */
1204         tag1->prev = tag;
1205         if(tag) tag->next = tag1;
1206         tag = tag1;
1207         swf_DeleteTag(0, tag2);
1208     } else {
1209         /* use the jpeg version- it's smaller */
1210         tag2->prev = tag;
1211         if(tag) tag->next = tag2;
1212         tag = tag2;
1213         swf_DeleteTag(0, tag1);
1214     }
1215     return tag;
1216 }
1217
1218 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1219 {
1220     RGBA *img;
1221     
1222     swf_SetTagPos(tag, 2); // id is 2 bytes
1223
1224     if (tag->id == ST_DEFINEBITSJPEG ||
1225         tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1226 #ifdef HAVE_JPEGLIB
1227         return swf_JPEG2TagToImage(tag, dwidth, dheight);
1228 #else
1229         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1230         return 0;
1231 #endif
1232     }
1233     if (tag->id == ST_DEFINEBITSLOSSLESS ||
1234         tag->id == ST_DEFINEBITSLOSSLESS2) {
1235 #ifdef HAVE_ZLIB
1236         return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1237 #else
1238         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1239         return 0;
1240 #endif
1241     }
1242     fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1243             swf_TagGetName(tag));
1244     return 0;
1245 }
1246
1247 #undef OUTBUFFER_SIZE
1248
1249
1250 void swf_RemoveJPEGTables(SWF * swf)
1251 {
1252     TAG *tag = swf->firstTag;
1253     TAG *tables_tag = 0;
1254     while (tag) {
1255         if (tag->id == ST_JPEGTABLES) {
1256             tables_tag = tag;
1257         }
1258         tag = tag->next;
1259     }
1260
1261     if (!tables_tag)
1262         return;
1263
1264     tag = swf->firstTag;
1265     while (tag) {
1266         if (tag->id == ST_DEFINEBITSJPEG) {
1267             int len = tag->len;
1268             void *data = rfx_alloc(len);
1269             swf_GetBlock(tag, (U8*)data, tag->len);
1270             swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1271             swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1272             swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1273             swf_SetBlock(tag, &((U8*)data)[2], len-2);
1274             free(data);
1275         }
1276         tag = tag->next;
1277     }
1278     if (swf->firstTag == tables_tag)
1279         swf->firstTag = tables_tag->next;
1280     swf_DeleteTag(swf, tables_tag);
1281 }
1282
1283 typedef struct scale_lookup {
1284     int pos;
1285     unsigned int weight;
1286 } scale_lookup_t;
1287
1288 typedef struct rgba_int {
1289     unsigned int r,g,b,a;
1290 } rgba_int_t;
1291
1292 static int bicubic = 0;
1293
1294 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1295 {
1296     scale_lookup_t*lookupx = (scale_lookup_t*)malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1297     scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1298     double fx = ((double)width)/((double)newwidth);
1299     double px = 0;
1300     int x;
1301     scale_lookup_t*p_x = lookupx;
1302
1303     if(newwidth<=width) {
1304         for(x=0;x<newwidth;x++) {
1305             double ex = px + fx;
1306             int fromx = (int)px;
1307             int tox = (int)ex;
1308             double rem = fromx+1-px;
1309             int i = (int)(256/fx);
1310             int xweight = (int)(rem*256/fx);
1311             int xx;
1312             int w = 0;
1313             lblockx[x] = p_x;
1314             if(tox>=width) tox = width-1;
1315             for(xx=fromx;xx<=tox;xx++) {
1316                 if(xx==fromx && xx==tox) p_x->weight = 256;
1317                 else if(xx==fromx) p_x->weight = xweight;
1318                 else if(xx==tox) p_x->weight = 256-w;
1319                 else p_x->weight = i;
1320                 w+=p_x->weight;
1321                 p_x->pos = xx;
1322                 p_x++;
1323             }
1324             px = ex;
1325         }
1326     } else {
1327         for(x=0;x<newwidth;x++) {
1328             int ix1 = (int)px;
1329             int ix2 = ((int)px)+1;
1330             double r = px-ix1;
1331             if(ix2>=width) ix2=width-1;
1332             lblockx[x] = p_x;
1333             if(bicubic)
1334                 r = -2*r*r*r+3*r*r;
1335             p_x[0].weight = (int)(256*(1-r));
1336             p_x[0].pos = ix1;
1337             p_x[1].weight = 256-p_x[0].weight;
1338             p_x[1].pos = ix2;
1339             p_x+=2;
1340             px += fx;
1341         }
1342     }
1343     lblockx[newwidth] = p_x;
1344     return lblockx;
1345 }
1346
1347 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1348 {
1349     int t;
1350     int len = width*height;
1351
1352     U32* img = (U32*)data;
1353     U32 color1 = img[0];
1354     U32 color2 = 0;
1355     for(t=1;t<len;t++) {
1356         if(img[t] != color1) {
1357             color2 = img[t];
1358             break;
1359         }
1360     }
1361     *(U32*)&colors[0] = color1;
1362     *(U32*)&colors[1] = color2;
1363     for(t=0;t<len;t++) {
1364         if(img[t] == color1) {
1365             img[t] = 0;
1366         } else {
1367             img[t] = 0xffffffff;
1368         }
1369     }
1370 }
1371
1372 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1373 {
1374     int t;
1375     int len = width*height;
1376
1377     for(t=0;t<len;t++) {
1378         U32 m = data[t].r;
1379         data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1380         data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1381         data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1382         data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1383     }
1384 }
1385
1386 static void blurImage(RGBA*src, int width, int height, int r)
1387 {
1388     int e = 2; // r times e is the sampling interval
1389     double*gauss = (double*)malloc(r*e*sizeof(double));
1390     double sum=0;
1391     int x;
1392     for(x=0;x<r*e;x++) {
1393         double t = (x - r*e/2.0)/r;
1394         gauss[x] = exp(-0.5*t*t);
1395         sum += gauss[x];
1396     }
1397     int*weights = (int*)malloc(r*e*sizeof(int));
1398     for(x=0;x<r*e;x++) {
1399         weights[x] = (int)(gauss[x]*65536.0001/sum);
1400     }
1401     int range = r*e/2;
1402
1403     RGBA*tmp = malloc(sizeof(RGBA)*width*height);
1404
1405     int y;
1406     for(y=0;y<height;y++) {
1407         RGBA*s = &src[y*width];
1408         RGBA*d = &tmp[y*width];
1409         for(x=0;x<range;x++) {
1410             d[x] = s[x];
1411         }
1412         for(x=range;x<width-range;x++) {
1413             int r=0;
1414             int g=0;
1415             int b=0;
1416             int a=0;
1417             int*f = weights;
1418             int xx;
1419             for(xx=x-range;xx<x+range;xx++) {
1420                 r += s[xx].r * f[0];
1421                 g += s[xx].g * f[0];
1422                 b += s[xx].b * f[0];
1423                 a += s[xx].a * f[0];
1424                 f++;
1425             }
1426             d[x].r = r >> 16;
1427             d[x].g = g >> 16;
1428             d[x].b = b >> 16;
1429             d[x].a = a >> 16;
1430         }
1431         for(x=width-range;x<width;x++) {
1432             d[x] = s[x];
1433         }
1434     }
1435
1436     for(x=0;x<width;x++) {
1437         RGBA*s = &tmp[x];
1438         RGBA*d = &src[x];
1439         int yy=0;
1440         for(y=0;y<range;y++) {
1441             d[yy] = s[yy];
1442             yy+=width;
1443         }
1444         for(y=range;y<height-range;y++) {
1445             int r=0;
1446             int g=0;
1447             int b=0;
1448             int a=0;
1449             int*f = weights;
1450             int cy,cyy=yy-range*width;
1451             for(cy=y-range;cy<y+range;cy++) {
1452                 r += s[cyy].r * f[0];
1453                 g += s[cyy].g * f[0];
1454                 b += s[cyy].b * f[0];
1455                 a += s[cyy].a * f[0];
1456                 cyy += width;
1457                 f++;
1458             }
1459             d[yy].r = r >> 16;
1460             d[yy].g = g >> 16;
1461             d[yy].b = b >> 16;
1462             d[yy].a = a >> 16;
1463             yy += width;
1464         }
1465         for(y=0;y<range;y++) {
1466             d[yy] = s[yy];
1467             yy += width;
1468         }
1469     }
1470
1471     free(tmp);
1472     free(weights);
1473     free(gauss);
1474 }
1475
1476
1477 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1478 {
1479     int x,y;
1480     RGBA* newdata; 
1481     scale_lookup_t *p, **lblockx,**lblocky;
1482     rgba_int_t*tmpline;
1483     int monochrome = 0;
1484     RGBA monochrome_colors[2];
1485     
1486     if(newwidth<1 || newheight<1)
1487         return 0;
1488
1489     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1490         monochrome=1;
1491         encodeMonochromeImage(data, width, height, monochrome_colors);
1492         int r1 = width / newwidth;
1493         int r2 = height / newheight;
1494         int r = r1<r2?r1:r2;
1495         if(r>4) {
1496             /* high-resolution monochrome images are usually dithered, so 
1497                low-pass filter them first to get rid of any moire patterns */
1498             blurImage(data, width, height, r+1);
1499         }
1500     }
1501
1502     tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1503     newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1504   
1505     lblockx = make_scale_lookup(width, newwidth);
1506     lblocky = make_scale_lookup(height, newheight);
1507
1508     for(p=lblocky[0];p<lblocky[newheight];p++)
1509         p->pos*=width;
1510
1511     for(y=0;y<newheight;y++) {
1512         RGBA*destline = &newdata[y*newwidth];
1513         
1514         /* create lookup table for y */
1515         rgba_int_t*l = tmpline;
1516         scale_lookup_t*p_y,*p_x;
1517         memset(tmpline, 0, width*sizeof(rgba_int_t));
1518         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1519             RGBA*line = &data[p_y->pos];
1520             scale_lookup_t*p_x;
1521             int weight = p_y->weight;
1522             for(x=0;x<width;x++) {
1523                 tmpline[x].r += line[x].r*weight;
1524                 tmpline[x].g += line[x].g*weight;
1525                 tmpline[x].b += line[x].b*weight;
1526                 tmpline[x].a += line[x].a*weight;
1527             }
1528         }
1529
1530         /* process x direction */
1531         p_x = lblockx[0];
1532         for(x=0;x<newwidth;x++) {
1533             unsigned int r=0,g=0,b=0,a=0;
1534             scale_lookup_t*p_x_to = lblockx[x+1];
1535             do { 
1536                 rgba_int_t* col = &tmpline[p_x->pos];
1537                 unsigned int weight = p_x->weight;
1538                 r += col->r*weight;
1539                 g += col->g*weight;
1540                 b += col->b*weight;
1541                 a += col->a*weight;
1542                 p_x++;
1543             } while (p_x<p_x_to);
1544
1545             destline->r = r >> 16;
1546             destline->g = g >> 16;
1547             destline->b = b >> 16;
1548             destline->a = a >> 16;
1549            
1550             destline++;
1551         }
1552     }
1553
1554     if(monochrome)
1555         decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);
1556
1557     free(tmpline);
1558     free(*lblockx);
1559     free(lblockx);
1560     free(*lblocky);
1561     free(lblocky);
1562     return newdata;
1563 }
1564
1565