added definejpeg3 extraction support
[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     if (tag->id == ST_DEFINEBITSJPEG3) {
406         swf_SetTagPos(tag, 6);
407     } else {
408         swf_SetTagPos(tag, 2);
409     }
410     cinfo->src->bytes_in_buffer = 0;
411 }
412 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
413 {
414     TAG *tag = (TAG *) cinfo->client_data;
415     if (tag->data[tag->pos + 0] == 0xff &&
416         tag->data[tag->pos + 1] == 0xd9 &&
417         tag->data[tag->pos + 2] == 0xff &&
418         tag->data[tag->pos + 3] == 0xd8) {
419         tag->pos += 4;
420     }
421     if (tag->pos >= tag->len) {
422         cinfo->src->next_input_byte = 0;
423         cinfo->src->bytes_in_buffer = 0;
424         return 0;
425     }
426     cinfo->src->next_input_byte = &tag->data[tag->pos];
427     cinfo->src->bytes_in_buffer = 1;    //tag->len - tag->pos;
428     tag->pos += 1;
429     return 1;
430 }
431 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
432 {
433     TAG *tag = (TAG *) cinfo->client_data;
434     cinfo->src->next_input_byte = 0;
435     cinfo->src->bytes_in_buffer = 0;
436     tag->pos += count;
437 }
438 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
439 {
440     return jpeg_resync_to_restart(cinfo, desired);
441 }
442 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
443 {
444     TAG *tag = (TAG *) cinfo->client_data;
445 }
446 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
447 {
448     struct jpeg_decompress_struct cinfo;
449     struct jpeg_error_mgr jerr;
450     struct jpeg_source_mgr mgr;
451     RGBA *dest;
452     int y;
453     *width = 0;
454     *height = 0;
455     int offset = 0;
456     int oldtaglen = 0;
457
458     if (tag->id == ST_DEFINEBITSJPEG) {
459         fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
460         return 0;
461     }
462     if (tag->id == ST_DEFINEBITSJPEG3) {
463 #ifdef HAVE_ZLIB
464         offset = swf_GetU32(tag);
465         oldtaglen = tag->len;
466         tag->len = offset+6;
467 #else
468         fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
469         return 0;
470 #endif
471     }
472
473     cinfo.err = jpeg_std_error(&jerr);
474     jpeg_create_decompress(&cinfo);
475
476     cinfo.client_data = (void *) tag;
477     cinfo.src = &mgr;
478     cinfo.src->init_source = tag_init_source;
479     cinfo.src->fill_input_buffer = tag_fill_input_buffer;
480     cinfo.src->skip_input_data = tag_skip_input_data;
481     cinfo.src->resync_to_restart = jpeg_resync_to_restart;
482     cinfo.src->term_source = tag_term_source;
483     cinfo.out_color_space = JCS_RGB;
484
485     jpeg_read_header(&cinfo, TRUE);
486     *width = cinfo.image_width;
487     *height = cinfo.image_height;
488     dest =
489         rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
490
491     jpeg_start_decompress(&cinfo);
492     for (y = 0; y < cinfo.output_height; y++) {
493         RGBA *line = &dest[y * cinfo.image_width];
494         U8 *to = (U8 *) line;
495         int x;
496         jpeg_read_scanlines(&cinfo, &to, 1);
497         for (x = cinfo.output_width - 1; x >= 0; --x) {
498             int r = to[x * 3 + 0];
499             int g = to[x * 3 + 1];
500             int b = to[x * 3 + 2];
501             line[x].r = r;
502             line[x].g = g;
503             line[x].b = b;
504             line[x].a = 255;
505         }
506     }
507
508     jpeg_finish_decompress(&cinfo);
509
510     jpeg_destroy_decompress(&cinfo);
511
512 #ifdef HAVE_ZLIB
513     if(offset) {
514         U32 datalen = cinfo.output_width*cinfo.output_height;
515         U8* alphadata = (U8*)rfx_alloc(datalen);
516         int error;
517         tag->len = oldtaglen;
518         swf_SetTagPos(tag, 6+offset);
519         error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
520         if (error != Z_OK) {
521             fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
522             return 0;
523         }
524         for(y=0;y<cinfo.output_height;y++) {
525             RGBA*line = &dest[y*cinfo.output_width];
526             U8*aline = &alphadata[y*cinfo.output_width];
527             int x;
528             for(x=0;x<cinfo.output_width;x++) {
529                 line[x].a = aline[x];
530             }
531         }
532         free(alphadata);
533     }
534 #endif
535     return dest;
536 }
537
538 #endif                          // HAVE_JPEGLIB
539
540 // Lossless compression texture based on zlib
541
542 #ifdef HAVE_ZLIB
543
544 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
545 {
546     U8 *data = rfx_alloc(OUTBUFFER_SIZE);
547     zs->next_out = data;
548     zs->avail_out = OUTBUFFER_SIZE;
549     while (1) {
550         int status = deflate(zs, Z_NO_FLUSH);
551
552         if (status != Z_OK) {
553             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
554             rfx_free(data);
555             return status;
556         }
557
558         if (zs->next_out != data) {
559             swf_SetBlock(t, data, zs->next_out - data);
560             zs->next_out = data;
561             zs->avail_out = OUTBUFFER_SIZE;
562         }
563
564         if (zs->avail_in == 0)
565             break;
566     }
567
568     if (!finish) {
569         rfx_free(data);
570         return 0;
571     }
572
573     while (1) {
574         int status = deflate(zs, Z_FINISH);
575         if (status != Z_OK && status != Z_STREAM_END) {
576             fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
577             rfx_free(data);
578             return status;
579         }
580
581         if (zs->next_out != data) {
582             swf_SetBlock(t, data, zs->next_out - data);
583             zs->next_out = data;
584             zs->avail_out = OUTBUFFER_SIZE;
585         }
586
587         if (status == Z_STREAM_END)
588             break;
589     }
590     rfx_free(data);
591     return 0;
592 }
593
594
595 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
596 {
597     int res = 0;
598     int bps;
599
600     switch (bitmap_flags) {
601     case BMF_8BIT:
602         return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
603     case BMF_16BIT:
604         bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
605         break;
606     case BMF_32BIT:
607         bps = width * 4;
608         break;
609     default:
610         fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
611         return -1;
612     }
613
614     swf_SetU8(t, bitmap_flags);
615     swf_SetU16(t, width);
616     swf_SetU16(t, height);
617
618     {
619         z_stream zs;
620
621         memset(&zs, 0x00, sizeof(z_stream));
622         zs.zalloc = Z_NULL;
623         zs.zfree = Z_NULL;
624
625         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
626             zs.avail_in = bps * height;
627             zs.next_in = bitmap;
628
629             if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
630                 res = -3;
631             deflateEnd(&zs);
632
633         } else
634             res = -3;           // zlib error
635     }
636     return res;
637 }
638
639 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
640 {
641     RGBA *pal = palette;
642     int bps = BYTES_PER_SCANLINE(width);
643     int res = 0;
644
645     if (!pal)                   // create default palette for grayscale images
646     {
647         int i;
648         pal = rfx_alloc(256 * sizeof(RGBA));
649         for (i = 0; i < 256; i++) {
650             pal[i].r = pal[i].g = pal[i].b = i;
651             pal[i].a = 0xff;
652         }
653         ncolors = 256;
654     }
655
656     if ((ncolors < 2) || (ncolors > 256) || (!t)) {
657         fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
658                 ncolors);
659         return -1;              // parameter error
660     }
661
662     swf_SetU8(t, BMF_8BIT);
663     swf_SetU16(t, width);
664     swf_SetU16(t, height);
665     swf_SetU8(t, ncolors - 1);  // number of pal entries
666
667     {
668         z_stream zs;
669
670         memset(&zs, 0x00, sizeof(z_stream));
671         zs.zalloc = Z_NULL;
672         zs.zfree = Z_NULL;
673
674         if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
675             U8 *zpal;           // compress palette
676             if ((zpal = rfx_alloc(ncolors * 4))) {
677                 U8 *pp = zpal;
678                 int i;
679
680                 /* be careful with ST_DEFINEBITSLOSSLESS2, because
681                    the Flash player produces great bugs if you use too many
682                    alpha colors in your palette. The only sensible result that
683                    can be archeived is setting one color to r=0,b=0,g=0,a=0 to
684                    make transparent parts in sprites. That's the cause why alpha
685                    handling is implemented in lossless routines of rfxswf.
686
687                    Indeed: I haven't understood yet how flash player handles
688                    alpha values different from 0 and 0xff in lossless bitmaps...
689                  */
690
691                 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2)  // have alpha channel?
692                 {
693                     for (i = 0; i < ncolors; i++) {
694                         pp[0] = pal[i].r;
695                         pp[1] = pal[i].g;
696                         pp[2] = pal[i].b;
697                         pp[3] = pal[i].a;
698                         pp += 4;
699                     }
700                     zs.avail_in = 4 * ncolors;
701                 } else {
702                     for (i = 0; i < ncolors; i++)       // pack RGBA structures to RGB 
703                     {
704                         pp[0] = pal[i].r;
705                         pp[1] = pal[i].g;
706                         pp[2] = pal[i].b;
707                         pp += 3;
708                     }
709                     zs.avail_in = 3 * ncolors;
710                 }
711
712                 zs.next_in = zpal;
713
714                 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
715                     res = -3;
716
717                 // compress bitmap
718                 zs.next_in = bitmap;
719                 zs.avail_in = (bps * height * sizeof(U8));
720
721                 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
722                     res = -3;
723
724                 deflateEnd(&zs);
725
726                 rfx_free(zpal);
727             } else
728                 res = -2;       // memory error
729         } else
730             res = -3;           // zlib error
731     }
732
733     if (!palette)
734         rfx_free(pal);
735
736     return res;
737 }
738
739 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
740 {
741     return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
742 }
743
744 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
745 {
746     int num = width*height;
747     int t;
748     for(t=0;t<num;t++) {
749         data[t].r = ((int)data[t].r*data[t].a)/255;
750         data[t].g = ((int)data[t].g*data[t].a)/255;
751         data[t].b = ((int)data[t].b*data[t].a)/255;
752     }
753 }
754
755 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
756 {
757     int hasalpha = swf_ImageHasAlpha(data, width, height);
758     int num;
759     if(!hasalpha) {
760         tag->id = ST_DEFINEBITSLOSSLESS;
761     } else {
762         tag->id = ST_DEFINEBITSLOSSLESS2;
763         swf_PreMultiplyAlpha(data, width, height);
764     }
765     num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
766     if(num>1 && num<=256) {
767         RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
768         int width2 = BYTES_PER_SCANLINE(width);
769         U8*data2 = (U8*)malloc(width2*height);
770         int len = width*height;
771         int x,y;
772         int r;
773         swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
774         for(y=0;y<height;y++) {
775             RGBA*src = &data[width*y];
776             U8*dest = &data2[width2*y];
777             for(x=0;x<width;x++) {
778                 RGBA col = src[x];
779                 for(r=0;r<num;r++) {
780                     if(*(U32*)&col == *(U32*)&palette[r]) {
781                         dest[x] = r;
782                         break;
783                     }
784                 }
785                 if(r==num) {
786                     fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
787                             col.r, col.g, col.b, col.a, num);
788                     dest[x] = 0;
789                 }
790             }
791         }
792         swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
793         free(data2);
794         free(palette);
795     } else {
796         swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
797     }
798 }
799
800 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
801 {
802     int id, format, height, width, pos;
803     U32 datalen, datalen2;
804     int error;
805     int bpp = 1;
806     int cols = 0;
807     int pos2 = 0;
808     char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
809     int t, x, y;
810     RGBA *palette = 0;
811     U8 *data, *data2;
812     RGBA *dest;
813     if (tag->id != ST_DEFINEBITSLOSSLESS &&
814         tag->id != ST_DEFINEBITSLOSSLESS2) {
815         fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
816                 GET16(tag->data));
817         return 0;
818     }
819     swf_SetTagPos(tag, 0);
820     id = swf_GetU16(tag);
821     format = swf_GetU8(tag);
822     if (format == 3)
823         bpp = 8;
824     if (format == 4)
825         bpp = 16;
826     if (format == 5)
827         bpp = 32;
828     if (format != 3 && format != 5) {
829         if (format == 4)
830             fprintf(stderr,
831                     "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
832                     id);
833         else
834             fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
835                     format, id);
836         return 0;
837     }
838     *dwidth = width = swf_GetU16(tag);
839     *dheight = height = swf_GetU16(tag);
840
841     dest = rfx_alloc(sizeof(RGBA) * width * height);
842
843     if (format == 3)
844         cols = swf_GetU8(tag) + 1;
845     else
846         cols = 0;
847
848     data = 0;
849     datalen = (width * height * bpp / 8 + cols * 8);
850     do {
851         if (data)
852             rfx_free(data);
853         datalen += 4096;
854         data = rfx_alloc(datalen);
855         error =
856             uncompress(data, &datalen, &tag->data[tag->pos],
857                        tag->len - tag->pos);
858     } while (error == Z_BUF_ERROR);
859     if (error != Z_OK) {
860         fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
861         return 0;
862     }
863     pos = 0;
864
865     if (cols) {
866         palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
867         for (t = 0; t < cols; t++) {
868             palette[t].r = data[pos++];
869             palette[t].g = data[pos++];
870             palette[t].b = data[pos++];
871             if (alpha) {
872                 palette[t].a = data[pos++];
873             } else {
874                 palette[t].a = 255;
875             }
876         }
877     }
878
879     for (y = 0; y < height; y++) {
880         int srcwidth = width * (bpp / 8);
881         if (bpp == 32) {
882             if (!alpha) {
883                 // 32 bit to 24 bit "conversion"
884                 for (x = 0; x < width; x++) {
885                     dest[pos2].r = data[pos + 1];
886                     dest[pos2].g = data[pos + 2];
887                     dest[pos2].b = data[pos + 3];
888                     dest[pos2].a = 255;
889                     pos2++;
890                     pos += 4;   //ignore padding byte
891                 }
892             } else {
893                 for (x = 0; x < width; x++) {
894                     /* TODO: is un-premultiplying alpha the right thing to do?
895                        dest[pos2].r = data[pos + 1];
896                        dest[pos2].g = data[pos + 2];
897                        dest[pos2].b = data[pos + 3];*/
898                     dest[pos2].r = ((int)data[pos + 1]*255)/(int)data[pos+0];
899                     dest[pos2].g = ((int)data[pos + 2]*255)/(int)data[pos+0];
900                     dest[pos2].b = ((int)data[pos + 3]*255)/(int)data[pos+0];
901                     dest[pos2].a = data[pos + 0];       //alpha
902                     pos2++;
903                     pos += 4;
904                 }
905             }
906         } else {
907             for (x = 0; x < srcwidth; x++) {
908                 dest[pos2] = palette[data[pos++]];
909                 pos2++;
910             }
911         }
912         pos += ((srcwidth + 3) & ~3) - srcwidth;        //align
913     }
914     if (palette)
915         rfx_free(palette);
916     rfx_free(data);
917     return dest;
918 }
919
920 #endif                          // HAVE_ZLIB
921
922 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
923 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
924 {
925     JPEGBITS *jpeg;
926     int y;
927     int pos;
928     int res = 0;
929     U8 *data;
930     z_stream zs;
931
932     pos = tag->len;
933     swf_SetU32(tag, 0);         //placeholder
934     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
935     for (y = 0; y < height; y++) {
936         U8 scanline[3 * width];
937         int x, p = 0;
938         for (x = 0; x < width; x++) {
939             scanline[p++] = bitmap[width * y + x].r;
940             scanline[p++] = bitmap[width * y + x].g;
941             scanline[p++] = bitmap[width * y + x].b;
942         }
943         swf_SetJPEGBitsLine(jpeg, scanline);
944     }
945     swf_SetJPEGBitsFinish(jpeg);
946     PUT32(&tag->data[pos], tag->len - pos - 4);
947
948     data = rfx_alloc(OUTBUFFER_SIZE);
949     memset(&zs, 0x00, sizeof(z_stream));
950
951     if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
952         fprintf(stderr, "rfxswf: zlib compression failed");
953         return -3;
954     }
955
956     zs.next_out = data;
957     zs.avail_out = OUTBUFFER_SIZE;
958
959     for (y = 0; y < height; y++) {
960         U8 scanline[width];
961         int x, p = 0;
962         for (x = 0; x < width; x++) {
963             scanline[p++] = bitmap[width * y + x].a;
964         }
965         zs.avail_in = width;
966         zs.next_in = scanline;
967
968         while (1) {
969             if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
970                 fprintf(stderr, "rfxswf: zlib compression failed");
971                 return -4;
972             }
973             if (zs.next_out != data) {
974                 swf_SetBlock(tag, data, zs.next_out - data);
975                 zs.next_out = data;
976                 zs.avail_out = OUTBUFFER_SIZE;
977             }
978             if (!zs.avail_in) {
979                 break;
980             }
981         }
982     }
983
984     while (1) {
985         int ret = deflate(&zs, Z_FINISH);
986         if (ret != Z_OK && ret != Z_STREAM_END) {
987             fprintf(stderr, "rfxswf: zlib compression failed");
988             return -5;
989         }
990         if (zs.next_out != data) {
991             swf_SetBlock(tag, data, zs.next_out - data);
992             zs.next_out = data;
993             zs.avail_out = OUTBUFFER_SIZE;
994         }
995         if (ret == Z_STREAM_END) {
996             break;
997         }
998     }
999
1000     deflateEnd(&zs);
1001     rfx_free(data);
1002     return 0;
1003 }
1004
1005 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1006 {
1007     TAG *tag1 = 0, *tag2 = 0;
1008     int has_alpha = swf_ImageHasAlpha(mem,width,height);
1009
1010     /* try lossless image */
1011     tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1012     swf_SetU16(tag1, bitid);
1013     swf_SetLosslessImage(tag1, mem, width, height);
1014
1015     /* try jpeg image */
1016     if(has_alpha) {
1017         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1018         swf_SetU16(tag2, bitid);
1019         swf_SetJPEGBits3(tag2, width, height, mem, quality);
1020     } else {
1021         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1022         swf_SetU16(tag2, bitid);
1023         swf_SetJPEGBits2(tag2, width, height, mem, quality);
1024     }
1025
1026     if(tag1 && tag1->len < tag2->len) {
1027         /* use the zlib version- it's smaller */
1028         tag1->prev = tag;
1029         if(tag) tag->next = tag1;
1030         tag = tag1;
1031         swf_DeleteTag(tag2);
1032     } else {
1033         /* use the jpeg version- it's smaller */
1034         tag2->prev = tag;
1035         if(tag) tag->next = tag2;
1036         tag = tag2;
1037         swf_DeleteTag(tag1);
1038     }
1039     return tag;
1040 }
1041
1042 #endif
1043
1044 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1045 {
1046     RGBA *img;
1047     
1048     swf_SetTagPos(tag, 2); // id is 2 bytes
1049
1050     if (tag->id == ST_DEFINEBITSJPEG ||
1051         tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1052 #ifdef HAVE_JPEGLIB
1053         return swf_JPEG2TagToImage(tag, dwidth, dheight);
1054 #else
1055         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1056         return 0;
1057 #endif
1058     }
1059     if (tag->id == ST_DEFINEBITSLOSSLESS ||
1060         tag->id == ST_DEFINEBITSLOSSLESS2) {
1061 #ifdef HAVE_ZLIB
1062         return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1063 #else
1064         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1065         return 0;
1066 #endif
1067     }
1068     fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1069             swf_TagGetName(tag));
1070     return 0;
1071 }
1072
1073 #undef OUTBUFFER_SIZE
1074
1075
1076 void swf_RemoveJPEGTables(SWF * swf)
1077 {
1078     TAG *tag = swf->firstTag;
1079     TAG *tables_tag = 0;
1080     while (tag) {
1081         if (tag->id == ST_JPEGTABLES) {
1082             tables_tag = tag;
1083         }
1084         tag = tag->next;
1085     }
1086
1087     if (!tables_tag)
1088         return;
1089
1090     tag = swf->firstTag;
1091     while (tag) {
1092         if (tag->id == ST_DEFINEBITSJPEG) {
1093             int len = tag->len;
1094             void *data = rfx_alloc(len);
1095             swf_GetBlock(tag, data, tag->len);
1096             swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1097             swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1098             swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1099             swf_SetBlock(tag, &((U8*)data)[2], len-2);
1100             free(data);
1101         }
1102         tag = tag->next;
1103     }
1104     if (swf->firstTag == tables_tag)
1105         swf->firstTag = tables_tag->next;
1106     swf_DeleteTag(tables_tag);
1107 }
1108
1109 typedef struct scale_lookup {
1110     int pos;
1111     unsigned int weight;
1112 } scale_lookup_t;
1113
1114 typedef struct rgba_int {
1115     unsigned int r,g,b,a;
1116 } rgba_int_t;
1117
1118 static int bicubic = 0;
1119
1120 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1121 {
1122     scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1123     scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1124     double fx = ((double)width)/((double)newwidth);
1125     double px = 0;
1126     int x;
1127     scale_lookup_t*p_x = lookupx;
1128
1129     if(newwidth<=width) {
1130         for(x=0;x<newwidth;x++) {
1131             double ex = px + fx;
1132             int fromx = (int)px;
1133             int tox = (int)ex;
1134             double rem = fromx+1-px;
1135             int i = (int)(256/fx);
1136             int xweight = (int)(rem*256/fx);
1137             int xx;
1138             int w = 0;
1139             lblockx[x] = p_x;
1140             if(tox>=width) tox = width-1;
1141             for(xx=fromx;xx<=tox;xx++) {
1142                 if(xx==fromx && xx==tox) p_x->weight = 256;
1143                 else if(xx==fromx) p_x->weight = xweight;
1144                 else if(xx==tox) p_x->weight = 256-w;
1145                 else p_x->weight = i;
1146                 w+=p_x->weight;
1147                 p_x->pos = xx;
1148                 p_x++;
1149             }
1150             px = ex;
1151         }
1152     } else {
1153         for(x=0;x<newwidth;x++) {
1154             int ix1 = (int)px;
1155             int ix2 = ((int)px)+1;
1156             double r = px-ix1;
1157             if(ix2>=width) ix2=width-1;
1158             lblockx[x] = p_x;
1159             if(bicubic)
1160                 r = -2*r*r*r+3*r*r;
1161             p_x[0].weight = (int)(256*(1-r));
1162             p_x[0].pos = ix1;
1163             p_x[1].weight = 256-p_x[0].weight;
1164             p_x[1].pos = ix2;
1165             p_x+=2;
1166             px += fx;
1167         }
1168     }
1169     lblockx[newwidth] = p_x;
1170     return lblockx;
1171 }
1172 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1173 {
1174     int x,y;
1175     RGBA* newdata; 
1176     scale_lookup_t *p, **lblockx,**lblocky;
1177     rgba_int_t*tmpline;
1178     
1179     if(newwidth<1 || newheight<1)
1180         return 0;
1181
1182     /* this is bad because this scaler doesn't yet handle monochrome
1183        images with 2 colors in a way that the final image hasn't more
1184        than 256 colors */
1185     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2)
1186         fprintf(stderr, "Warning: scaling monochrome image\n");
1187
1188     tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1189     newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1190   
1191     lblockx = make_scale_lookup(width, newwidth);
1192     lblocky = make_scale_lookup(height, newheight);
1193
1194     for(p=lblocky[0];p<lblocky[newheight];p++)
1195         p->pos*=width;
1196
1197     for(y=0;y<newheight;y++) {
1198         RGBA*destline = &newdata[y*newwidth];
1199         
1200         /* create lookup table for y */
1201         rgba_int_t*l = tmpline;
1202         scale_lookup_t*p_y,*p_x;
1203         memset(tmpline, 0, width*sizeof(rgba_int_t));
1204         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1205             RGBA*line = &data[p_y->pos];
1206             scale_lookup_t*p_x;
1207             int weight = p_y->weight;
1208             for(x=0;x<width;x++) {
1209                 tmpline[x].r += line[x].r*weight;
1210                 tmpline[x].g += line[x].g*weight;
1211                 tmpline[x].b += line[x].b*weight;
1212                 tmpline[x].a += line[x].a*weight;
1213             }
1214         }
1215
1216         /* process x direction */
1217         p_x = lblockx[0];
1218         for(x=0;x<newwidth;x++) {
1219             unsigned int r=0,g=0,b=0,a=0;
1220             scale_lookup_t*p_x_to = lblockx[x+1];
1221             do { 
1222                 rgba_int_t* col = &tmpline[p_x->pos];
1223                 unsigned int weight = p_x->weight;
1224                 r += col->r*weight;
1225                 g += col->g*weight;
1226                 b += col->b*weight;
1227                 a += col->a*weight;
1228                 p_x++;
1229             } while (p_x<p_x_to);
1230
1231             destline->r = r >> 16;
1232             destline->g = g >> 16;
1233             destline->b = b >> 16;
1234             destline->a = a >> 16;
1235            
1236             destline++;
1237         }
1238     }
1239     free(tmpline);
1240     free(*lblockx);
1241     free(lblockx);
1242     free(*lblocky);
1243     free(lblocky);
1244     return newdata;
1245 }
1246