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