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