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