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