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