fixed jpegtable merging
[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         return width*height;
155     if(palette) {
156         int i = 0;
157         for(t=0;t<256;t++) {
158             int s;
159             int csize = size[t];
160             U32* cpal = &pal[t*256];
161             for(s=0;s<csize;s++)
162                 palette[i++] = *(RGBA*)(&cpal[s]);
163         }
164     }
165     free(pal);
166     return palsize;
167 }
168
169
170
171 #ifdef HAVE_JPEGLIB
172
173 typedef struct _JPEGDESTMGR {
174     struct jpeg_destination_mgr mgr;
175     TAG *t;
176     JOCTET *buffer;
177     struct jpeg_compress_struct cinfo;
178     struct jpeg_error_mgr jerr;
179 } JPEGDESTMGR, *LPJPEGDESTMGR;
180
181 // Destination manager callbacks
182
183 static void RFXSWF_init_destination(j_compress_ptr cinfo)
184 {
185     JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
186     dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
187     dmgr->mgr.next_output_byte = dmgr->buffer;
188     dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
189 }
190
191 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
192 {
193     JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
194     swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
195     dmgr->mgr.next_output_byte = dmgr->buffer;
196     dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
197     return TRUE;
198 }
199
200 static void RFXSWF_term_destination(j_compress_ptr cinfo)
201 {
202     JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
203     swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
204                  OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
205     rfx_free(dmgr->buffer);
206     dmgr->mgr.free_in_buffer = 0;
207 }
208
209 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
210 {
211     JPEGDESTMGR *jpeg;
212
213     // redirect compression lib output to local SWF Tag structure
214
215     jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
216
217     jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
218
219     jpeg_create_compress(&jpeg->cinfo);
220
221     jpeg->mgr.init_destination = RFXSWF_init_destination;
222     jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
223     jpeg->mgr.term_destination = RFXSWF_term_destination;
224
225     jpeg->t = t;
226
227     jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
228
229     // init compression
230
231     jpeg->cinfo.image_width = width;
232     jpeg->cinfo.image_height = height;
233     jpeg->cinfo.input_components = 3;
234     jpeg->cinfo.in_color_space = JCS_RGB;
235
236     jpeg_set_defaults(&jpeg->cinfo);
237     jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
238
239     // write tables to SWF
240
241     jpeg_write_tables(&jpeg->cinfo);
242
243     // compess image to SWF
244
245     jpeg_suppress_tables(&jpeg->cinfo, TRUE);
246     jpeg_start_compress(&jpeg->cinfo, FALSE);
247
248     return (JPEGBITS *) jpeg;
249 }
250
251 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
252 {
253     JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
254     if (!jpeg)
255         return -1;
256     jpeg_write_scanlines(&jpeg->cinfo, data, n);
257     return 0;
258 }
259
260 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
261 {
262     return swf_SetJPEGBitsLines(jpegbits, &data, 1);
263 }
264
265 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
266 {
267     JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
268     if (!jpeg)
269         return -1;
270     jpeg_finish_compress(&jpeg->cinfo);
271     rfx_free(jpeg);
272     return 0;
273 }
274
275 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
276                       int quality)
277 {
278     JPEGBITS *jpeg;
279     int y;
280     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
281     for (y = 0; y < height; y++) {
282         U8 scanline[3 * width];
283         int x, p = 0;
284         for (x = 0; x < width; x++) {
285             scanline[p++] = bitmap[width * y + x].r;
286             scanline[p++] = bitmap[width * y + x].g;
287             scanline[p++] = bitmap[width * y + x].b;
288         }
289         swf_SetJPEGBitsLine(jpeg, scanline);
290     }
291     swf_SetJPEGBitsFinish(jpeg);
292 }
293
294 void swf_GetJPEGSize(char *fname, int *width, int *height)
295 {
296     struct jpeg_decompress_struct cinfo;
297     struct jpeg_error_mgr jerr;
298     FILE *fi;
299     *width = 0;
300     *height = 0;
301     cinfo.err = jpeg_std_error(&jerr);
302     jpeg_create_decompress(&cinfo);
303     if ((fi = fopen(fname, "rb")) == NULL) {
304         fprintf(stderr, "rfxswf: file open error\n");
305         return;
306     }
307     jpeg_stdio_src(&cinfo, fi);
308     jpeg_read_header(&cinfo, TRUE);
309     *width = cinfo.image_width;
310     *height = cinfo.image_height;
311     jpeg_destroy_decompress(&cinfo);
312     fclose(fi);
313 }
314
315 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
316 {
317     struct jpeg_decompress_struct cinfo;
318     struct jpeg_error_mgr jerr;
319     JPEGBITS *out;
320     FILE *f;
321     U8 *scanline;
322
323     cinfo.err = jpeg_std_error(&jerr);
324     jpeg_create_decompress(&cinfo);
325
326     if ((f = fopen(fname, "rb")) == NULL) {
327         fprintf(stderr, "rfxswf: file open error\n");
328         return -1;
329     }
330
331     jpeg_stdio_src(&cinfo, f);
332     jpeg_read_header(&cinfo, TRUE);
333     jpeg_start_decompress(&cinfo);
334
335     out =
336         swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
337                              quality);
338     scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
339
340     if (scanline) {
341         int y;
342         U8 *js = scanline;
343         if (cinfo.out_color_space == JCS_GRAYSCALE) {
344             for (y = 0; y < cinfo.output_height; y++) {
345                 int x;
346                 jpeg_read_scanlines(&cinfo, &js, 1);
347                 for (x = cinfo.output_width - 1; x >= 0; x--) {
348                     js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
349                 }
350                 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
351             }
352         } else if (cinfo.out_color_space == JCS_RGB) {
353             for (y = 0; y < cinfo.output_height; y++) {
354                 jpeg_read_scanlines(&cinfo, &js, 1);
355                 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
356             }
357         } else if (cinfo.out_color_space == JCS_YCCK) {
358             //FIXME
359             fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
360             return -1;
361         } else if (cinfo.out_color_space == JCS_YCbCr) {
362             for (y = 0; y < cinfo.output_height; y++) {
363                 int x;
364                 for (x = 0; x < cinfo.output_width; x++) {
365                     int y = js[x * 3 + 0];
366                     int u = js[x * 3 + 1];
367                     int v = js[x * 3 + 1];
368                     js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
369                     js[x * 3 + 1] =
370                         y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
371                     js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
372                 }
373             }
374         } else if (cinfo.out_color_space == JCS_CMYK) {
375             for (y = 0; y < cinfo.output_height; y++) {
376                 int x;
377                 jpeg_read_scanlines(&cinfo, &js, 1);
378                 /* This routine seems to work for now-
379                    It's a mixture of 3 different
380                    CMYK->RGB conversion routines I found in the
381                    web. (which all produced garbage)
382                    I'm happily accepting suggestions. (mk) */
383                 for (x = 0; x < cinfo.output_width; x++) {
384                     int white = 255 - js[x * 4 + 3];
385                     js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
386                     js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
387                     js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
388                 }
389                 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
390             }
391         }
392     }
393
394     swf_SetJPEGBitsFinish(out);
395     jpeg_finish_decompress(&cinfo);
396     fclose(f);
397
398     return 0;
399 }
400
401 /*  jpeg_source_mgr functions */
402 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
403 {
404     TAG *tag = (TAG *) cinfo->client_data;
405     swf_SetTagPos(tag, 2);
406     cinfo->src->bytes_in_buffer = 0;
407 }
408 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
409 {
410     TAG *tag = (TAG *) cinfo->client_data;
411     if (tag->data[tag->pos + 0] == 0xff &&
412         tag->data[tag->pos + 1] == 0xd9 &&
413         tag->data[tag->pos + 2] == 0xff &&
414         tag->data[tag->pos + 3] == 0xd8) {
415         tag->pos += 4;
416     }
417     if (tag->pos >= tag->len) {
418         cinfo->src->next_input_byte = 0;
419         cinfo->src->bytes_in_buffer = 0;
420         return 0;
421     }
422     cinfo->src->next_input_byte = &tag->data[tag->pos];
423     cinfo->src->bytes_in_buffer = 1;    //tag->len - tag->pos;
424     tag->pos += 1;
425     return 1;
426 }
427 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
428 {
429     TAG *tag = (TAG *) cinfo->client_data;
430     cinfo->src->next_input_byte = 0;
431     cinfo->src->bytes_in_buffer = 0;
432     tag->pos += count;
433 }
434 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
435 {
436     return jpeg_resync_to_restart(cinfo, desired);
437 }
438 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
439 {
440     TAG *tag = (TAG *) cinfo->client_data;
441 }
442 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
443 {
444     struct jpeg_decompress_struct cinfo;
445     struct jpeg_error_mgr jerr;
446     struct jpeg_source_mgr mgr;
447     RGBA *dest;
448     int y;
449     *width = 0;
450     *height = 0;
451
452     if (tag->id == ST_DEFINEBITSJPEG) {
453         fprintf(stderr,
454                 "rfxswf: extracting from definebitsjpeg not yet supported");
455         return 0;
456     }
457     if (tag->id == ST_DEFINEBITSJPEG3) {
458         fprintf(stderr,
459                 "rfxswf: extracting from definebitsjpeg3 not yet supported");
460         return 0;
461     }
462
463     cinfo.err = jpeg_std_error(&jerr);
464     jpeg_create_decompress(&cinfo);
465
466     cinfo.client_data = (void *) tag;
467     cinfo.src = &mgr;
468     cinfo.src->init_source = tag_init_source;
469     cinfo.src->fill_input_buffer = tag_fill_input_buffer;
470     cinfo.src->skip_input_data = tag_skip_input_data;
471     cinfo.src->resync_to_restart = jpeg_resync_to_restart;
472     cinfo.src->term_source = tag_term_source;
473     cinfo.out_color_space = JCS_RGB;
474
475     jpeg_read_header(&cinfo, TRUE);
476     *width = cinfo.image_width;
477     *height = cinfo.image_height;
478     dest =
479         rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
480
481     jpeg_start_decompress(&cinfo);
482     for (y = 0; y < cinfo.output_height; y++) {
483         RGBA *line = &dest[y * cinfo.image_width];
484         U8 *to = (U8 *) line;
485         int x;
486         jpeg_read_scanlines(&cinfo, &to, 1);
487         for (x = cinfo.output_width - 1; x >= 0; --x) {
488             int r = to[x * 3 + 0];
489             int g = to[x * 3 + 1];
490             int b = to[x * 3 + 2];
491             line[x].r = r;
492             line[x].g = g;
493             line[x].b = b;
494             line[x].a = 255;
495         }
496     }
497
498     jpeg_finish_decompress(&cinfo);
499
500     jpeg_destroy_decompress(&cinfo);
501     return dest;
502 }
503
504 #endif                          // HAVE_JPEGLIB
505
506 // Lossless compression texture based on zlib
507
508 #ifdef HAVE_ZLIB
509
510 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
511 {
512     U8 *data = rfx_alloc(OUTBUFFER_SIZE);
513     zs->next_out = data;
514     zs->avail_out = OUTBUFFER_SIZE;
515     while (1) {
516         int status = deflate(zs, Z_NO_FLUSH);
517
518         if (status != Z_OK) {
519             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
520             rfx_free(data);
521             return status;
522         }
523
524         if (zs->next_out != data) {
525             swf_SetBlock(t, data, zs->next_out - data);
526             zs->next_out = data;
527             zs->avail_out = OUTBUFFER_SIZE;
528         }
529
530         if (zs->avail_in == 0)
531             break;
532     }
533
534     if (!finish) {
535         rfx_free(data);
536         return 0;
537     }
538
539     while (1) {
540         int status = deflate(zs, Z_FINISH);
541         if (status != Z_OK && status != Z_STREAM_END) {
542             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
543             rfx_free(data);
544             return status;
545         }
546
547         if (zs->next_out != data) {
548             swf_SetBlock(t, data, zs->next_out - data);
549             zs->next_out = data;
550             zs->avail_out = OUTBUFFER_SIZE;
551         }
552
553         if (status == Z_STREAM_END)
554             break;
555     }
556     rfx_free(data);
557     return 0;
558 }
559
560
561 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
562 {
563     int res = 0;
564     int bps;
565
566     switch (bitmap_flags) {
567     case BMF_8BIT:
568         return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
569     case BMF_16BIT:
570         bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
571         break;
572     case BMF_32BIT:
573         bps = width * 4;
574         break;
575     default:
576         fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
577         return -1;
578     }
579
580     swf_SetU8(t, bitmap_flags);
581     swf_SetU16(t, width);
582     swf_SetU16(t, height);
583
584     {
585         z_stream zs;
586
587         memset(&zs, 0x00, sizeof(z_stream));
588         zs.zalloc = Z_NULL;
589         zs.zfree = Z_NULL;
590
591         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
592             zs.avail_in = bps * height;
593             zs.next_in = bitmap;
594
595             if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
596                 res = -3;
597             deflateEnd(&zs);
598
599         } else
600             res = -3;           // zlib error
601     }
602     return res;
603 }
604
605 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
606 {
607     RGBA *pal = palette;
608     int bps = BYTES_PER_SCANLINE(width);
609     int res = 0;
610
611     if (!pal)                   // create default palette for grayscale images
612     {
613         int i;
614         pal = rfx_alloc(256 * sizeof(RGBA));
615         for (i = 0; i < 256; i++) {
616             pal[i].r = pal[i].g = pal[i].b = i;
617             pal[i].a = 0xff;
618         }
619         ncolors = 256;
620     }
621
622     if ((ncolors < 2) || (ncolors > 256) || (!t)) {
623         fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
624                 ncolors);
625         return -1;              // parameter error
626     }
627
628     swf_SetU8(t, BMF_8BIT);
629     swf_SetU16(t, width);
630     swf_SetU16(t, height);
631     swf_SetU8(t, ncolors - 1);  // number of pal entries
632
633     {
634         z_stream zs;
635
636         memset(&zs, 0x00, sizeof(z_stream));
637         zs.zalloc = Z_NULL;
638         zs.zfree = Z_NULL;
639
640         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
641             U8 *zpal;           // compress palette
642             if ((zpal = rfx_alloc(ncolors * 4))) {
643                 U8 *pp = zpal;
644                 int i;
645
646                 /* be careful with ST_DEFINEBITSLOSSLESS2, because
647                    the Flash player produces great bugs if you use too many
648                    alpha colors in your palette. The only sensible result that
649                    can be archeived is setting one color to r=0,b=0,g=0,a=0 to
650                    make transparent parts in sprites. That's the cause why alpha
651                    handling is implemented in lossless routines of rfxswf.
652
653                    Indeed: I haven't understood yet how flash player handles
654                    alpha values different from 0 and 0xff in lossless bitmaps...
655                  */
656
657                 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2)  // have alpha channel?
658                 {
659                     for (i = 0; i < ncolors; i++) {
660                         pp[0] = pal[i].r;
661                         pp[1] = pal[i].g;
662                         pp[2] = pal[i].b;
663                         pp[3] = pal[i].a;
664                         pp += 4;
665                     }
666                     zs.avail_in = 4 * ncolors;
667                 } else {
668                     for (i = 0; i < ncolors; i++)       // pack RGBA structures to RGB 
669                     {
670                         pp[0] = pal[i].r;
671                         pp[1] = pal[i].g;
672                         pp[2] = pal[i].b;
673                         pp += 3;
674                     }
675                     zs.avail_in = 3 * ncolors;
676                 }
677
678                 zs.next_in = zpal;
679
680                 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
681                     res = -3;
682
683                 // compress bitmap
684                 zs.next_in = bitmap;
685                 zs.avail_in = (bps * height * sizeof(U8));
686
687                 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
688                     res = -3;
689
690                 deflateEnd(&zs);
691
692                 rfx_free(zpal);
693             } else
694                 res = -2;       // memory error
695         } else
696             res = -3;           // zlib error
697     }
698
699     if (!palette)
700         rfx_free(pal);
701
702     return res;
703 }
704
705 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
706 {
707     return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
708 }
709
710 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
711 {
712     int hasalpha = swf_ImageHasAlpha(data, width, height);
713     int num;
714     if(!hasalpha) {
715         tag->id = ST_DEFINEBITSLOSSLESS;
716     } else {
717         tag->id = ST_DEFINEBITSLOSSLESS2;
718         /* TODO: premultiply alpha? */
719     }
720     num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
721     if(num>1 && num<=256) {
722         RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
723         int width2 = BYTES_PER_SCANLINE(width);
724         U8*data2 = (U8*)malloc(width2*height);
725         int len = width*height;
726         int x,y;
727         int r;
728         swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
729         for(y=0;y<height;y++) {
730             RGBA*src = &data[width*y];
731             U8*dest = &data2[width2*y];
732             for(x=0;x<width;x++) {
733                 RGBA col = src[x];
734                 for(r=0;r<num;r++) {
735                     if(*(U32*)&col == *(U32*)&palette[r]) {
736                         dest[x] = r;
737                         break;
738                     }
739                 }
740                 if(r==num) {
741                     fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
742                             col.r, col.g, col.b, col.a, num);
743                     dest[x] = 0;
744                 }
745             }
746         }
747         swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
748         free(data2);
749         free(palette);
750     } else {
751         swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
752     }
753 }
754
755 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
756 {
757     int id, format, height, width, pos;
758     U32 datalen, datalen2;
759     int error;
760     int bpp = 1;
761     int cols = 0;
762     int pos2 = 0;
763     char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
764     int t, x, y;
765     RGBA *palette = 0;
766     U8 *data, *data2;
767     RGBA *dest;
768     if (tag->id != ST_DEFINEBITSLOSSLESS &&
769         tag->id != ST_DEFINEBITSLOSSLESS2) {
770         fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
771                 GET16(tag->data));
772         return 0;
773     }
774     swf_SetTagPos(tag, 0);
775     id = swf_GetU16(tag);
776     format = swf_GetU8(tag);
777     if (format == 3)
778         bpp = 8;
779     if (format == 4)
780         bpp = 16;
781     if (format == 5)
782         bpp = 32;
783     if (format != 3 && format != 5) {
784         if (format == 4)
785             fprintf(stderr,
786                     "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
787                     id);
788         else
789             fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
790                     format, id);
791         return 0;
792     }
793     *dwidth = width = swf_GetU16(tag);
794     *dheight = height = swf_GetU16(tag);
795
796     dest = rfx_alloc(sizeof(RGBA) * width * height);
797
798     if (format == 3)
799         cols = swf_GetU8(tag) + 1;
800     else
801         cols = 0;
802
803     data = 0;
804     datalen = (width * height * bpp / 8 + cols * 8);
805     do {
806         if (data)
807             rfx_free(data);
808         datalen += 4096;
809         data = rfx_alloc(datalen);
810         error =
811             uncompress(data, &datalen, &tag->data[tag->pos],
812                        tag->len - tag->pos);
813     } while (error == Z_BUF_ERROR);
814     if (error != Z_OK) {
815         fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
816         return 0;
817     }
818     pos = 0;
819
820     if (cols) {
821         palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
822         for (t = 0; t < cols; t++) {
823             palette[t].r = data[pos++];
824             palette[t].g = data[pos++];
825             palette[t].b = data[pos++];
826             if (alpha) {
827                 palette[t].a = data[pos++];
828             } else {
829                 palette[t].a = 255;
830             }
831         }
832     }
833
834     for (y = 0; y < height; y++) {
835         int srcwidth = width * (bpp / 8);
836         if (bpp == 32) {
837             if (!alpha) {
838                 // 32 bit to 24 bit "conversion"
839                 for (x = 0; x < width; x++) {
840                     dest[pos2].r = data[pos + 1];
841                     dest[pos2].g = data[pos + 2];
842                     dest[pos2].b = data[pos + 3];
843                     dest[pos2].a = 255;
844                     pos2++;
845                     pos += 4;   //ignore padding byte
846                 }
847             } else {
848                 for (x = 0; x < width; x++) {
849                     /* TODO: premultiply alpha? 
850                     dest[pos2].r = (data[pos + 1]*255)/data[pos+0];
851                     dest[pos2].g = (data[pos + 2]*255)/data[pos+0];
852                     dest[pos2].b = (data[pos + 3]*255)/data[pos+0];
853                     */
854                     dest[pos2].r = data[pos + 1];
855                     dest[pos2].g = data[pos + 2];
856                     dest[pos2].b = data[pos + 3];
857                     dest[pos2].a = data[pos + 0];       //alpha
858                     pos2++;
859                     pos += 4;
860                 }
861             }
862         } else {
863             for (x = 0; x < srcwidth; x++) {
864                 dest[pos2] = palette[data[pos++]];
865                 pos2++;
866             }
867         }
868         pos += ((srcwidth + 3) & ~3) - srcwidth;        //align
869     }
870     if (palette)
871         rfx_free(palette);
872     rfx_free(data);
873     return dest;
874 }
875
876 #endif                          // HAVE_ZLIB
877
878 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
879 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
880 {
881     JPEGBITS *jpeg;
882     int y;
883     int pos;
884     int res = 0;
885     U8 *data;
886     z_stream zs;
887
888     pos = tag->len;
889     swf_SetU32(tag, 0);         //placeholder
890     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
891     for (y = 0; y < height; y++) {
892         U8 scanline[3 * width];
893         int x, p = 0;
894         for (x = 0; x < width; x++) {
895             scanline[p++] = bitmap[width * y + x].r;
896             scanline[p++] = bitmap[width * y + x].g;
897             scanline[p++] = bitmap[width * y + x].b;
898         }
899         swf_SetJPEGBitsLine(jpeg, scanline);
900     }
901     swf_SetJPEGBitsFinish(jpeg);
902     PUT32(&tag->data[pos], tag->len - pos - 4);
903
904     data = rfx_alloc(OUTBUFFER_SIZE);
905     memset(&zs, 0x00, sizeof(z_stream));
906
907     if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
908         fprintf(stderr, "rfxswf: zlib compression failed");
909         return -3;
910     }
911
912     zs.next_out = data;
913     zs.avail_out = OUTBUFFER_SIZE;
914
915     for (y = 0; y < height; y++) {
916         U8 scanline[width];
917         int x, p = 0;
918         for (x = 0; x < width; x++) {
919             scanline[p++] = bitmap[width * y + x].a;
920         }
921         zs.avail_in = width;
922         zs.next_in = scanline;
923
924         while (1) {
925             if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
926                 fprintf(stderr, "rfxswf: zlib compression failed");
927                 return -4;
928             }
929             if (zs.next_out != data) {
930                 swf_SetBlock(tag, data, zs.next_out - data);
931                 zs.next_out = data;
932                 zs.avail_out = OUTBUFFER_SIZE;
933             }
934             if (!zs.avail_in) {
935                 break;
936             }
937         }
938     }
939
940     while (1) {
941         int ret = deflate(&zs, Z_FINISH);
942         if (ret != Z_OK && ret != Z_STREAM_END) {
943             fprintf(stderr, "rfxswf: zlib compression failed");
944             return -5;
945         }
946         if (zs.next_out != data) {
947             swf_SetBlock(tag, data, zs.next_out - data);
948             zs.next_out = data;
949             zs.avail_out = OUTBUFFER_SIZE;
950         }
951         if (ret == Z_STREAM_END) {
952             break;
953         }
954     }
955
956     deflateEnd(&zs);
957     rfx_free(data);
958     return 0;
959 }
960
961 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
962 {
963     TAG *tag1 = 0, *tag2 = 0;
964     int has_alpha = swf_ImageHasAlpha(mem,width,height);
965
966     /* try lossless image */
967     tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
968     swf_SetU16(tag1, bitid);
969     swf_SetLosslessImage(tag1, mem, width, height);
970
971     /* try jpeg image */
972     if(has_alpha) {
973         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
974         swf_SetU16(tag2, bitid);
975         swf_SetJPEGBits3(tag2, width, height, mem, quality);
976     } else {
977         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
978         swf_SetU16(tag2, bitid);
979         swf_SetJPEGBits2(tag2, width, height, mem, quality);
980     }
981
982     if(tag1 && tag1->len < tag2->len) {
983         /* use the zlib version- it's smaller */
984         tag1->prev = tag;
985         if(tag) tag->next = tag1;
986         tag = tag1;
987         swf_DeleteTag(tag2);
988     } else {
989         /* use the jpeg version- it's smaller */
990         tag2->prev = tag;
991         if(tag) tag->next = tag2;
992         tag = tag2;
993         swf_DeleteTag(tag1);
994     }
995     return tag;
996 }
997
998 #endif
999
1000 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1001 {
1002     RGBA *img;
1003     if (tag->id == ST_DEFINEBITSJPEG ||
1004         tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1005 #ifdef HAVE_JPEGLIB
1006         return swf_JPEG2TagToImage(tag, dwidth, dheight);
1007 #else
1008         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1009         return 0;
1010 #endif
1011     }
1012     if (tag->id == ST_DEFINEBITSLOSSLESS ||
1013         tag->id == ST_DEFINEBITSLOSSLESS2) {
1014 #ifdef HAVE_ZLIB
1015         return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1016 #else
1017         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1018         return 0;
1019 #endif
1020     }
1021     fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1022             swf_TagGetName(tag));
1023     return 0;
1024 }
1025
1026 #undef OUTBUFFER_SIZE
1027
1028
1029 void swf_RemoveJPEGTables(SWF * swf)
1030 {
1031     TAG *tag = swf->firstTag;
1032     TAG *tables_tag = 0;
1033     while (tag) {
1034         if (tag->id == ST_JPEGTABLES) {
1035             tables_tag = tag;
1036         }
1037         tag = tag->next;
1038     }
1039
1040     if (!tables_tag)
1041         return;
1042
1043     tag = swf->firstTag;
1044     while (tag) {
1045         if (tag->id == ST_DEFINEBITSJPEG) {
1046             int len = tag->len;
1047             void *data = rfx_alloc(len);
1048             swf_GetBlock(tag, data, tag->len);
1049             swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1050             swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1051             swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1052             swf_SetBlock(tag, &((U8*)data)[2], len-2);
1053             free(data);
1054         }
1055         tag = tag->next;
1056     }
1057     if (swf->firstTag == tables_tag)
1058         swf->firstTag = tables_tag->next;
1059     swf_DeleteTag(tables_tag);
1060 }
1061
1062 typedef struct scale_lookup {
1063     int pos;
1064     unsigned int weight;
1065 } scale_lookup_t;
1066
1067 typedef struct rgba_int {
1068     unsigned int r,g,b,a;
1069 } rgba_int_t;
1070
1071 static int bicubic = 0;
1072
1073 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1074 {
1075     scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1076     scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1077     double fx = ((double)width)/((double)newwidth);
1078     double px = 0;
1079     int x;
1080     scale_lookup_t*p_x = lookupx;
1081
1082     if(newwidth<=width) {
1083         for(x=0;x<newwidth;x++) {
1084             double ex = px + fx;
1085             int fromx = (int)px;
1086             int tox = (int)ex;
1087             double rem = fromx+1-px;
1088             int i = (int)(256/fx);
1089             int xweight = (int)(rem*256/fx);
1090             int xx;
1091             int w = 0;
1092             lblockx[x] = p_x;
1093             if(tox>=width) tox = width-1;
1094             for(xx=fromx;xx<=tox;xx++) {
1095                 if(xx==fromx && xx==tox) p_x->weight = 256;
1096                 else if(xx==fromx) p_x->weight = xweight;
1097                 else if(xx==tox) p_x->weight = 256-w;
1098                 else p_x->weight = i;
1099                 w+=p_x->weight;
1100                 p_x->pos = xx;
1101                 p_x++;
1102             }
1103             px = ex;
1104         }
1105     } else {
1106         for(x=0;x<newwidth;x++) {
1107             int ix1 = (int)px;
1108             int ix2 = ((int)px)+1;
1109             double r = px-ix1;
1110             if(ix2>=width) ix2=width-1;
1111             lblockx[x] = p_x;
1112             if(bicubic)
1113                 r = -2*r*r*r+3*r*r;
1114             p_x[0].weight = (int)(256*(1-r));
1115             p_x[0].pos = ix1;
1116             p_x[1].weight = 256-p_x[0].weight;
1117             p_x[1].pos = ix2;
1118             p_x+=2;
1119             px += fx;
1120         }
1121     }
1122     lblockx[newwidth] = p_x;
1123     return lblockx;
1124 }
1125 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1126 {
1127     int x,y;
1128     RGBA* newdata; 
1129     scale_lookup_t *p, **lblockx,**lblocky;
1130     rgba_int_t*tmpline;
1131     
1132     if(newwidth<1 || newheight<1)
1133         return 0;
1134
1135     /* this is bad because this scaler doesn't yet handle monochrome
1136        images with 2 colors in a way that the final image hasn't more
1137        than 256 colors */
1138     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2)
1139         fprintf(stderr, "Warning: scaling monochrome image\n");
1140
1141     tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1142     newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1143   
1144     lblockx = make_scale_lookup(width, newwidth);
1145     lblocky = make_scale_lookup(height, newheight);
1146
1147     for(p=lblocky[0];p<lblocky[newheight];p++)
1148         p->pos*=width;
1149
1150     for(y=0;y<newheight;y++) {
1151         RGBA*destline = &newdata[y*newwidth];
1152         
1153         /* create lookup table for y */
1154         rgba_int_t*l = tmpline;
1155         scale_lookup_t*p_y,*p_x;
1156         memset(tmpline, 0, width*sizeof(rgba_int_t));
1157         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1158             RGBA*line = &data[p_y->pos];
1159             scale_lookup_t*p_x;
1160             int weight = p_y->weight;
1161             for(x=0;x<width;x++) {
1162                 tmpline[x].r += line[x].r*weight;
1163                 tmpline[x].g += line[x].g*weight;
1164                 tmpline[x].b += line[x].b*weight;
1165                 tmpline[x].a += line[x].a*weight;
1166             }
1167         }
1168
1169         /* process x direction */
1170         p_x = lblockx[0];
1171         for(x=0;x<newwidth;x++) {
1172             unsigned int r=0,g=0,b=0,a=0;
1173             scale_lookup_t*p_x_to = lblockx[x+1];
1174             do { 
1175                 rgba_int_t* col = &tmpline[p_x->pos];
1176                 unsigned int weight = p_x->weight;
1177                 r += col->r*weight;
1178                 g += col->g*weight;
1179                 b += col->b*weight;
1180                 a += col->a*weight;
1181                 p_x++;
1182             } while (p_x<p_x_to);
1183
1184             destline->r = r >> 16;
1185             destline->g = g >> 16;
1186             destline->b = b >> 16;
1187             destline->a = a >> 16;
1188            
1189             destline++;
1190         }
1191     }
1192     free(tmpline);
1193     free(*lblockx);
1194     free(lblockx);
1195     free(*lblocky);
1196     free(lblocky);
1197     return newdata;
1198 }
1199