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