added pre-multiplying / un-premultiplying stuff.
[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_PreMultiplyAlpha(RGBA*data, int width, int height)
711 {
712     int num = width*height;
713     int t;
714     for(t=0;t<num;t++) {
715         data[t].r = ((int)data[t].r*data[t].a)/255;
716         data[t].g = ((int)data[t].g*data[t].a)/255;
717         data[t].b = ((int)data[t].b*data[t].a)/255;
718     }
719 }
720
721 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
722 {
723     int hasalpha = swf_ImageHasAlpha(data, width, height);
724     int num;
725     if(!hasalpha) {
726         tag->id = ST_DEFINEBITSLOSSLESS;
727     } else {
728         tag->id = ST_DEFINEBITSLOSSLESS2;
729         swf_PreMultiplyAlpha(data, width, height);
730     }
731     num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
732     if(num>1 && num<=256) {
733         RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
734         int width2 = BYTES_PER_SCANLINE(width);
735         U8*data2 = (U8*)malloc(width2*height);
736         int len = width*height;
737         int x,y;
738         int r;
739         swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
740         for(y=0;y<height;y++) {
741             RGBA*src = &data[width*y];
742             U8*dest = &data2[width2*y];
743             for(x=0;x<width;x++) {
744                 RGBA col = src[x];
745                 for(r=0;r<num;r++) {
746                     if(*(U32*)&col == *(U32*)&palette[r]) {
747                         dest[x] = r;
748                         break;
749                     }
750                 }
751                 if(r==num) {
752                     fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
753                             col.r, col.g, col.b, col.a, num);
754                     dest[x] = 0;
755                 }
756             }
757         }
758         swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
759         free(data2);
760         free(palette);
761     } else {
762         swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
763     }
764 }
765
766 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
767 {
768     int id, format, height, width, pos;
769     U32 datalen, datalen2;
770     int error;
771     int bpp = 1;
772     int cols = 0;
773     int pos2 = 0;
774     char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
775     int t, x, y;
776     RGBA *palette = 0;
777     U8 *data, *data2;
778     RGBA *dest;
779     if (tag->id != ST_DEFINEBITSLOSSLESS &&
780         tag->id != ST_DEFINEBITSLOSSLESS2) {
781         fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
782                 GET16(tag->data));
783         return 0;
784     }
785     swf_SetTagPos(tag, 0);
786     id = swf_GetU16(tag);
787     format = swf_GetU8(tag);
788     if (format == 3)
789         bpp = 8;
790     if (format == 4)
791         bpp = 16;
792     if (format == 5)
793         bpp = 32;
794     if (format != 3 && format != 5) {
795         if (format == 4)
796             fprintf(stderr,
797                     "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
798                     id);
799         else
800             fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
801                     format, id);
802         return 0;
803     }
804     *dwidth = width = swf_GetU16(tag);
805     *dheight = height = swf_GetU16(tag);
806
807     dest = rfx_alloc(sizeof(RGBA) * width * height);
808
809     if (format == 3)
810         cols = swf_GetU8(tag) + 1;
811     else
812         cols = 0;
813
814     data = 0;
815     datalen = (width * height * bpp / 8 + cols * 8);
816     do {
817         if (data)
818             rfx_free(data);
819         datalen += 4096;
820         data = rfx_alloc(datalen);
821         error =
822             uncompress(data, &datalen, &tag->data[tag->pos],
823                        tag->len - tag->pos);
824     } while (error == Z_BUF_ERROR);
825     if (error != Z_OK) {
826         fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
827         return 0;
828     }
829     pos = 0;
830
831     if (cols) {
832         palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
833         for (t = 0; t < cols; t++) {
834             palette[t].r = data[pos++];
835             palette[t].g = data[pos++];
836             palette[t].b = data[pos++];
837             if (alpha) {
838                 palette[t].a = data[pos++];
839             } else {
840                 palette[t].a = 255;
841             }
842         }
843     }
844
845     for (y = 0; y < height; y++) {
846         int srcwidth = width * (bpp / 8);
847         if (bpp == 32) {
848             if (!alpha) {
849                 // 32 bit to 24 bit "conversion"
850                 for (x = 0; x < width; x++) {
851                     dest[pos2].r = data[pos + 1];
852                     dest[pos2].g = data[pos + 2];
853                     dest[pos2].b = data[pos + 3];
854                     dest[pos2].a = 255;
855                     pos2++;
856                     pos += 4;   //ignore padding byte
857                 }
858             } else {
859                 for (x = 0; x < width; x++) {
860                     /* TODO: is un-premultiplying alpha the right thing to do?
861                        dest[pos2].r = data[pos + 1];
862                        dest[pos2].g = data[pos + 2];
863                        dest[pos2].b = data[pos + 3];*/
864                     dest[pos2].r = ((int)data[pos + 1]*255)/(int)data[pos+0];
865                     dest[pos2].g = ((int)data[pos + 2]*255)/(int)data[pos+0];
866                     dest[pos2].b = ((int)data[pos + 3]*255)/(int)data[pos+0];
867                     dest[pos2].a = data[pos + 0];       //alpha
868                     pos2++;
869                     pos += 4;
870                 }
871             }
872         } else {
873             for (x = 0; x < srcwidth; x++) {
874                 dest[pos2] = palette[data[pos++]];
875                 pos2++;
876             }
877         }
878         pos += ((srcwidth + 3) & ~3) - srcwidth;        //align
879     }
880     if (palette)
881         rfx_free(palette);
882     rfx_free(data);
883     return dest;
884 }
885
886 #endif                          // HAVE_ZLIB
887
888 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
889 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
890 {
891     JPEGBITS *jpeg;
892     int y;
893     int pos;
894     int res = 0;
895     U8 *data;
896     z_stream zs;
897
898     pos = tag->len;
899     swf_SetU32(tag, 0);         //placeholder
900     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
901     for (y = 0; y < height; y++) {
902         U8 scanline[3 * width];
903         int x, p = 0;
904         for (x = 0; x < width; x++) {
905             scanline[p++] = bitmap[width * y + x].r;
906             scanline[p++] = bitmap[width * y + x].g;
907             scanline[p++] = bitmap[width * y + x].b;
908         }
909         swf_SetJPEGBitsLine(jpeg, scanline);
910     }
911     swf_SetJPEGBitsFinish(jpeg);
912     PUT32(&tag->data[pos], tag->len - pos - 4);
913
914     data = rfx_alloc(OUTBUFFER_SIZE);
915     memset(&zs, 0x00, sizeof(z_stream));
916
917     if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
918         fprintf(stderr, "rfxswf: zlib compression failed");
919         return -3;
920     }
921
922     zs.next_out = data;
923     zs.avail_out = OUTBUFFER_SIZE;
924
925     for (y = 0; y < height; y++) {
926         U8 scanline[width];
927         int x, p = 0;
928         for (x = 0; x < width; x++) {
929             scanline[p++] = bitmap[width * y + x].a;
930         }
931         zs.avail_in = width;
932         zs.next_in = scanline;
933
934         while (1) {
935             if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
936                 fprintf(stderr, "rfxswf: zlib compression failed");
937                 return -4;
938             }
939             if (zs.next_out != data) {
940                 swf_SetBlock(tag, data, zs.next_out - data);
941                 zs.next_out = data;
942                 zs.avail_out = OUTBUFFER_SIZE;
943             }
944             if (!zs.avail_in) {
945                 break;
946             }
947         }
948     }
949
950     while (1) {
951         int ret = deflate(&zs, Z_FINISH);
952         if (ret != Z_OK && ret != Z_STREAM_END) {
953             fprintf(stderr, "rfxswf: zlib compression failed");
954             return -5;
955         }
956         if (zs.next_out != data) {
957             swf_SetBlock(tag, data, zs.next_out - data);
958             zs.next_out = data;
959             zs.avail_out = OUTBUFFER_SIZE;
960         }
961         if (ret == Z_STREAM_END) {
962             break;
963         }
964     }
965
966     deflateEnd(&zs);
967     rfx_free(data);
968     return 0;
969 }
970
971 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
972 {
973     TAG *tag1 = 0, *tag2 = 0;
974     int has_alpha = swf_ImageHasAlpha(mem,width,height);
975
976     /* try lossless image */
977     tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
978     swf_SetU16(tag1, bitid);
979     swf_SetLosslessImage(tag1, mem, width, height);
980
981     /* try jpeg image */
982     if(has_alpha) {
983         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
984         swf_SetU16(tag2, bitid);
985         swf_SetJPEGBits3(tag2, width, height, mem, quality);
986     } else {
987         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
988         swf_SetU16(tag2, bitid);
989         swf_SetJPEGBits2(tag2, width, height, mem, quality);
990     }
991
992     if(tag1 && tag1->len < tag2->len) {
993         /* use the zlib version- it's smaller */
994         tag1->prev = tag;
995         if(tag) tag->next = tag1;
996         tag = tag1;
997         swf_DeleteTag(tag2);
998     } else {
999         /* use the jpeg version- it's smaller */
1000         tag2->prev = tag;
1001         if(tag) tag->next = tag2;
1002         tag = tag2;
1003         swf_DeleteTag(tag1);
1004     }
1005     return tag;
1006 }
1007
1008 #endif
1009
1010 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1011 {
1012     RGBA *img;
1013     if (tag->id == ST_DEFINEBITSJPEG ||
1014         tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1015 #ifdef HAVE_JPEGLIB
1016         return swf_JPEG2TagToImage(tag, dwidth, dheight);
1017 #else
1018         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1019         return 0;
1020 #endif
1021     }
1022     if (tag->id == ST_DEFINEBITSLOSSLESS ||
1023         tag->id == ST_DEFINEBITSLOSSLESS2) {
1024 #ifdef HAVE_ZLIB
1025         return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1026 #else
1027         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1028         return 0;
1029 #endif
1030     }
1031     fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1032             swf_TagGetName(tag));
1033     return 0;
1034 }
1035
1036 #undef OUTBUFFER_SIZE
1037
1038
1039 void swf_RemoveJPEGTables(SWF * swf)
1040 {
1041     TAG *tag = swf->firstTag;
1042     TAG *tables_tag = 0;
1043     while (tag) {
1044         if (tag->id == ST_JPEGTABLES) {
1045             tables_tag = tag;
1046         }
1047         tag = tag->next;
1048     }
1049
1050     if (!tables_tag)
1051         return;
1052
1053     tag = swf->firstTag;
1054     while (tag) {
1055         if (tag->id == ST_DEFINEBITSJPEG) {
1056             int len = tag->len;
1057             void *data = rfx_alloc(len);
1058             swf_GetBlock(tag, data, tag->len);
1059             swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1060             swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1061             swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1062             swf_SetBlock(tag, &((U8*)data)[2], len-2);
1063             free(data);
1064         }
1065         tag = tag->next;
1066     }
1067     if (swf->firstTag == tables_tag)
1068         swf->firstTag = tables_tag->next;
1069     swf_DeleteTag(tables_tag);
1070 }
1071
1072 typedef struct scale_lookup {
1073     int pos;
1074     unsigned int weight;
1075 } scale_lookup_t;
1076
1077 typedef struct rgba_int {
1078     unsigned int r,g,b,a;
1079 } rgba_int_t;
1080
1081 static int bicubic = 0;
1082
1083 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1084 {
1085     scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1086     scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1087     double fx = ((double)width)/((double)newwidth);
1088     double px = 0;
1089     int x;
1090     scale_lookup_t*p_x = lookupx;
1091
1092     if(newwidth<=width) {
1093         for(x=0;x<newwidth;x++) {
1094             double ex = px + fx;
1095             int fromx = (int)px;
1096             int tox = (int)ex;
1097             double rem = fromx+1-px;
1098             int i = (int)(256/fx);
1099             int xweight = (int)(rem*256/fx);
1100             int xx;
1101             int w = 0;
1102             lblockx[x] = p_x;
1103             if(tox>=width) tox = width-1;
1104             for(xx=fromx;xx<=tox;xx++) {
1105                 if(xx==fromx && xx==tox) p_x->weight = 256;
1106                 else if(xx==fromx) p_x->weight = xweight;
1107                 else if(xx==tox) p_x->weight = 256-w;
1108                 else p_x->weight = i;
1109                 w+=p_x->weight;
1110                 p_x->pos = xx;
1111                 p_x++;
1112             }
1113             px = ex;
1114         }
1115     } else {
1116         for(x=0;x<newwidth;x++) {
1117             int ix1 = (int)px;
1118             int ix2 = ((int)px)+1;
1119             double r = px-ix1;
1120             if(ix2>=width) ix2=width-1;
1121             lblockx[x] = p_x;
1122             if(bicubic)
1123                 r = -2*r*r*r+3*r*r;
1124             p_x[0].weight = (int)(256*(1-r));
1125             p_x[0].pos = ix1;
1126             p_x[1].weight = 256-p_x[0].weight;
1127             p_x[1].pos = ix2;
1128             p_x+=2;
1129             px += fx;
1130         }
1131     }
1132     lblockx[newwidth] = p_x;
1133     return lblockx;
1134 }
1135 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1136 {
1137     int x,y;
1138     RGBA* newdata; 
1139     scale_lookup_t *p, **lblockx,**lblocky;
1140     rgba_int_t*tmpline;
1141     
1142     if(newwidth<1 || newheight<1)
1143         return 0;
1144
1145     /* this is bad because this scaler doesn't yet handle monochrome
1146        images with 2 colors in a way that the final image hasn't more
1147        than 256 colors */
1148     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2)
1149         fprintf(stderr, "Warning: scaling monochrome image\n");
1150
1151     tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1152     newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1153   
1154     lblockx = make_scale_lookup(width, newwidth);
1155     lblocky = make_scale_lookup(height, newheight);
1156
1157     for(p=lblocky[0];p<lblocky[newheight];p++)
1158         p->pos*=width;
1159
1160     for(y=0;y<newheight;y++) {
1161         RGBA*destline = &newdata[y*newwidth];
1162         
1163         /* create lookup table for y */
1164         rgba_int_t*l = tmpline;
1165         scale_lookup_t*p_y,*p_x;
1166         memset(tmpline, 0, width*sizeof(rgba_int_t));
1167         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1168             RGBA*line = &data[p_y->pos];
1169             scale_lookup_t*p_x;
1170             int weight = p_y->weight;
1171             for(x=0;x<width;x++) {
1172                 tmpline[x].r += line[x].r*weight;
1173                 tmpline[x].g += line[x].g*weight;
1174                 tmpline[x].b += line[x].b*weight;
1175                 tmpline[x].a += line[x].a*weight;
1176             }
1177         }
1178
1179         /* process x direction */
1180         p_x = lblockx[0];
1181         for(x=0;x<newwidth;x++) {
1182             unsigned int r=0,g=0,b=0,a=0;
1183             scale_lookup_t*p_x_to = lblockx[x+1];
1184             do { 
1185                 rgba_int_t* col = &tmpline[p_x->pos];
1186                 unsigned int weight = p_x->weight;
1187                 r += col->r*weight;
1188                 g += col->g*weight;
1189                 b += col->b*weight;
1190                 a += col->a*weight;
1191                 p_x++;
1192             } while (p_x<p_x_to);
1193
1194             destline->r = r >> 16;
1195             destline->g = g >> 16;
1196             destline->b = b >> 16;
1197             destline->a = a >> 16;
1198            
1199             destline++;
1200         }
1201     }
1202     free(tmpline);
1203     free(*lblockx);
1204     free(lblockx);
1205     free(*lblocky);
1206     free(lblocky);
1207     return newdata;
1208 }
1209