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