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