gcc 2.95.x fixes
[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             }
805         }
806     }
807
808     for (y = 0; y < height; y++) {
809         int srcwidth = width * (bpp / 8);
810         if (bpp == 32) {
811             if (!alpha) {
812                 // 32 bit to 24 bit "conversion"
813                 for (x = 0; x < width; x++) {
814                     dest[pos2].r = data[pos + 1];
815                     dest[pos2].g = data[pos + 2];
816                     dest[pos2].b = data[pos + 3];
817                     dest[pos2].a = 255;
818                     pos2++;
819                     pos += 4;   //ignore padding byte
820                 }
821             } else {
822                 for (x = 0; x < width; x++) {
823                     /* TODO: un-premultiply alpha? */
824                     dest[pos2].r = data[pos + 1];
825                     dest[pos2].g = data[pos + 2];
826                     dest[pos2].b = data[pos + 3];
827                     dest[pos2].a = data[pos + 0];       //alpha
828                     pos2++;
829                     pos += 4;
830                 }
831             }
832         } else {
833             for (x = 0; x < srcwidth; x++) {
834                 dest[pos2] = palette[data[pos++]];
835                 pos2++;
836             }
837         }
838         pos += ((srcwidth + 3) & ~3) - srcwidth;        //align
839     }
840     if (palette)
841         rfx_free(palette);
842     rfx_free(data);
843     return dest;
844 }
845
846 #endif                          // HAVE_ZLIB
847
848 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
849 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
850 {
851     JPEGBITS *jpeg;
852     int y;
853     int pos;
854     int res = 0;
855     U8 *data;
856     z_stream zs;
857
858     pos = tag->len;
859     swf_SetU32(tag, 0);         //placeholder
860     jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
861     for (y = 0; y < height; y++) {
862         U8 scanline[3 * width];
863         int x, p = 0;
864         for (x = 0; x < width; x++) {
865             scanline[p++] = bitmap[width * y + x].r;
866             scanline[p++] = bitmap[width * y + x].g;
867             scanline[p++] = bitmap[width * y + x].b;
868         }
869         swf_SetJPEGBitsLine(jpeg, scanline);
870     }
871     swf_SetJPEGBitsFinish(jpeg);
872     PUT32(&tag->data[pos], tag->len - pos - 4);
873
874     data = rfx_alloc(OUTBUFFER_SIZE);
875     memset(&zs, 0x00, sizeof(z_stream));
876
877     if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
878         fprintf(stderr, "rfxswf: zlib compression failed");
879         return -3;
880     }
881
882     zs.next_out = data;
883     zs.avail_out = OUTBUFFER_SIZE;
884
885     for (y = 0; y < height; y++) {
886         U8 scanline[width];
887         int x, p = 0;
888         for (x = 0; x < width; x++) {
889             scanline[p++] = bitmap[width * y + x].a;
890         }
891         zs.avail_in = width;
892         zs.next_in = scanline;
893
894         while (1) {
895             if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
896                 fprintf(stderr, "rfxswf: zlib compression failed");
897                 return -4;
898             }
899             if (zs.next_out != data) {
900                 swf_SetBlock(tag, data, zs.next_out - data);
901                 zs.next_out = data;
902                 zs.avail_out = OUTBUFFER_SIZE;
903             }
904             if (!zs.avail_in) {
905                 break;
906             }
907         }
908     }
909
910     while (1) {
911         int ret = deflate(&zs, Z_FINISH);
912         if (ret != Z_OK && ret != Z_STREAM_END) {
913             fprintf(stderr, "rfxswf: zlib compression failed");
914             return -5;
915         }
916         if (zs.next_out != data) {
917             swf_SetBlock(tag, data, zs.next_out - data);
918             zs.next_out = data;
919             zs.avail_out = OUTBUFFER_SIZE;
920         }
921         if (ret == Z_STREAM_END) {
922             break;
923         }
924     }
925
926     deflateEnd(&zs);
927     rfx_free(data);
928     return 0;
929 }
930
931 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
932 {
933     TAG *tag1 = 0, *tag2 = 0;
934     int has_alpha = swf_ImageHasAlpha(mem,width,height);
935
936     /* try lossless image */
937     tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
938     swf_SetU16(tag1, bitid);
939     swf_SetLosslessImage(tag1, mem, width, height);
940
941     /* try jpeg image */
942     if(has_alpha) {
943         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
944         swf_SetU16(tag2, bitid);
945         swf_SetJPEGBits3(tag2, width, height, mem, quality);
946     } else {
947         tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
948         swf_SetU16(tag2, bitid);
949         swf_SetJPEGBits2(tag2, width, height, mem, quality);
950     }
951
952     if(tag1 && tag1->len < tag2->len) {
953         /* use the zlib version- it's smaller */
954         tag1->prev = tag;
955         if(tag) tag->next = tag1;
956         tag = tag1;
957         swf_DeleteTag(tag2);
958     } else {
959         /* use the jpeg version- it's smaller */
960         tag2->prev = tag;
961         if(tag) tag->next = tag2;
962         tag = tag2;
963         swf_DeleteTag(tag1);
964     }
965     return tag;
966 }
967
968 #endif
969
970 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
971 {
972     RGBA *img;
973     if (tag->id == ST_DEFINEBITSJPEG ||
974         tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
975 #ifdef HAVE_JPEGLIB
976         return swf_JPEG2TagToImage(tag, dwidth, dheight);
977 #else
978         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
979         return 0;
980 #endif
981     }
982     if (tag->id == ST_DEFINEBITSLOSSLESS ||
983         tag->id == ST_DEFINEBITSLOSSLESS2) {
984 #ifdef HAVE_ZLIB
985         return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
986 #else
987         fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
988         return 0;
989 #endif
990     }
991     fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
992             swf_TagGetName(tag));
993     return 0;
994 }
995
996 #undef OUTBUFFER_SIZE
997
998
999 void swf_RemoveJPEGTables(SWF * swf)
1000 {
1001     TAG *tag = swf->firstTag;
1002     TAG *tables_tag = 0;
1003     while (tag) {
1004         if (tag->id == ST_JPEGTABLES) {
1005             tables_tag = tag;
1006         }
1007         tag = tag->next;
1008     }
1009
1010     if (!tables_tag)
1011         return;
1012
1013     tag = swf->firstTag;
1014     while (tag) {
1015         if (tag->id == ST_DEFINEBITSJPEG) {
1016             void *data = rfx_alloc(tag->len);
1017             swf_GetBlock(tag, data, tag->len);
1018             swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1019             swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1020             swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1021             swf_SetBlock(tag, &((U8*)data)[2], tag->len-2);
1022             free(data);
1023         }
1024         tag = tag->next;
1025     }
1026     if (swf->firstTag == tables_tag)
1027         swf->firstTag = tables_tag->next;
1028     swf_DeleteTag(tables_tag);
1029 }
1030
1031 typedef struct scale_lookup {
1032     int pos;
1033     unsigned int weight;
1034 } scale_lookup_t;
1035
1036 typedef struct rgba_int {
1037     unsigned int r,g,b,a;
1038 } rgba_int_t;
1039
1040 static int bicubic = 0;
1041
1042 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1043 {
1044     scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1045     scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1046     double fx = ((double)width)/((double)newwidth);
1047     double px = 0;
1048     int x;
1049     scale_lookup_t*p_x = lookupx;
1050
1051     if(newwidth<=width) {
1052         for(x=0;x<newwidth;x++) {
1053             double ex = px + fx;
1054             int fromx = (int)px;
1055             int tox = (int)ex;
1056             double rem = fromx+1-px;
1057             int i = (int)(256/fx);
1058             int xweight = (int)(rem*256/fx);
1059             int xx;
1060             int w = 0;
1061             lblockx[x] = p_x;
1062             if(tox>=width) tox = width-1;
1063             for(xx=fromx;xx<=tox;xx++) {
1064                 if(xx==fromx && xx==tox) p_x->weight = 256;
1065                 else if(xx==fromx) p_x->weight = xweight;
1066                 else if(xx==tox) p_x->weight = 256-w;
1067                 else p_x->weight = i;
1068                 w+=p_x->weight;
1069                 p_x->pos = xx;
1070                 p_x++;
1071             }
1072             px = ex;
1073         }
1074     } else {
1075         for(x=0;x<newwidth;x++) {
1076             int ix1 = (int)px;
1077             int ix2 = ((int)px)+1;
1078             double r = px-ix1;
1079             if(ix2>=width) ix2=width-1;
1080             lblockx[x] = p_x;
1081             if(bicubic)
1082                 r = -2*r*r*r+3*r*r;
1083             p_x[0].weight = (int)(256*(1-r));
1084             p_x[0].pos = ix1;
1085             p_x[1].weight = 256-p_x[0].weight;
1086             p_x[1].pos = ix2;
1087             p_x+=2;
1088             px += fx;
1089         }
1090     }
1091     lblockx[newwidth] = p_x;
1092     return lblockx;
1093 }
1094
1095 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1096 {
1097     int x,y;
1098     RGBA* newdata; 
1099     scale_lookup_t *p, **lblockx,**lblocky;
1100     rgba_int_t*tmpline;
1101     
1102     if(newwidth<1 || newheight<1)
1103         return 0;
1104
1105     tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1106     newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1107   
1108     lblockx = make_scale_lookup(width, newwidth);
1109     lblocky = make_scale_lookup(height, newheight);
1110
1111     for(p=lblocky[0];p<lblocky[newheight];p++)
1112         p->pos*=width;
1113
1114     for(y=0;y<newheight;y++) {
1115         RGBA*destline = &newdata[y*newwidth];
1116         
1117         /* create lookup table for y */
1118         rgba_int_t*l = tmpline;
1119         scale_lookup_t*p_y,*p_x;
1120         memset(tmpline, 0, width*sizeof(rgba_int_t));
1121         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1122             RGBA*line = &data[p_y->pos];
1123             scale_lookup_t*p_x;
1124             int weight = p_y->weight;
1125             for(x=0;x<width;x++) {
1126                 tmpline[x].r += line[x].r*weight;
1127                 tmpline[x].g += line[x].g*weight;
1128                 tmpline[x].b += line[x].b*weight;
1129                 tmpline[x].a += line[x].a*weight;
1130             }
1131         }
1132
1133         /* process x direction */
1134         p_x = lblockx[0];
1135         for(x=0;x<newwidth;x++) {
1136             unsigned int r=0,g=0,b=0,a=0;
1137             scale_lookup_t*p_x_to = lblockx[x+1];
1138             do { 
1139                 rgba_int_t* col = &tmpline[p_x->pos];
1140                 unsigned int weight = p_x->weight;
1141                 r += col->r*weight;
1142                 g += col->g*weight;
1143                 b += col->b*weight;
1144                 a += col->a*weight;
1145                 p_x++;
1146             } while (p_x<p_x_to);
1147
1148             destline->r = r >> 16;
1149             destline->g = g >> 16;
1150             destline->b = b >> 16;
1151             destline->a = a >> 16;
1152            
1153             destline++;
1154         }
1155     }
1156     free(tmpline);
1157     free(*lblockx);
1158     free(lblockx);
1159     free(*lblocky);
1160     free(lblocky);
1161     return newdata;
1162 }
1163