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