3 Bitmap functions (needs libjpeg)
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
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.
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.
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 */
32 #define OUTBUFFER_SIZE 0x8000
34 int swf_ImageHasAlpha(RGBA*img, int width, int height)
36 int len = width*height;
40 if(img[t].a >= 4 && img[t].a < 0xfc)
48 int swf_ImageGetNumberOfPaletteEntries2(RGBA*_img, int width, int height)
50 int len = width*height;
52 U32* img = (U32*)_img;
56 if(img[t] != color1) {
65 if(img[t] != color1 && img[t] != color2) {
72 /*int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
74 int len = width*height;
79 int palette_overflow = 0;
82 if(sizeof(RGBA)!=sizeof(U32))
83 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
85 lastcol32 = pal32[palsize++] = *(U32*)&img[0];
89 U32 col32 = *(U32*)&img[t];
93 for(i=0;i<palsize;i++) {
102 pal32[palsize++] = col32;
109 memcpy(palette, pal, palsize*sizeof(RGBA));
113 int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
115 int len = width*height;
120 int palette_overflow = 0;
123 pal = (U32*)malloc(65536*sizeof(U32));
125 memset(size, 0, sizeof(size));
127 if(sizeof(RGBA)!=sizeof(U32))
128 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
130 lastcol32 = (*(U32*)&img[0])^0xffffffff; // don't match
134 U32 col32 = *(U32*)&img[t];
139 if(col32 == lastcol32)
141 hash = (col32 >> 17) ^ col32;
142 hash ^= ((hash>>8) + 1) ^ hash;
146 cpal = &pal[hash*256];
147 for(i=0;i<csize;i++) {
153 palette_overflow = 1;
156 cpal[size[hash]++] = col32;
161 if(palette_overflow) {
170 U32* cpal = &pal[t*256];
172 palette[i++] = *(RGBA*)(&cpal[s]);
183 typedef struct _JPEGDESTMGR {
184 struct jpeg_destination_mgr mgr;
187 struct jpeg_compress_struct cinfo;
188 struct jpeg_error_mgr jerr;
189 } JPEGDESTMGR, *LPJPEGDESTMGR;
191 // Destination manager callbacks
193 static void RFXSWF_init_destination(j_compress_ptr cinfo)
195 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
196 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
197 dmgr->mgr.next_output_byte = dmgr->buffer;
198 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
201 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
203 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
204 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
205 dmgr->mgr.next_output_byte = dmgr->buffer;
206 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
210 static void RFXSWF_term_destination(j_compress_ptr cinfo)
212 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
213 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
214 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
215 rfx_free(dmgr->buffer);
216 dmgr->mgr.free_in_buffer = 0;
219 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
223 // redirect compression lib output to local SWF Tag structure
225 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
227 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
229 jpeg_create_compress(&jpeg->cinfo);
231 jpeg->mgr.init_destination = RFXSWF_init_destination;
232 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
233 jpeg->mgr.term_destination = RFXSWF_term_destination;
237 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
241 jpeg->cinfo.image_width = width;
242 jpeg->cinfo.image_height = height;
243 jpeg->cinfo.input_components = 3;
244 jpeg->cinfo.in_color_space = JCS_RGB;
246 jpeg_set_defaults(&jpeg->cinfo);
247 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
249 // write tables to SWF
251 jpeg_write_tables(&jpeg->cinfo);
253 // compess image to SWF
255 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
256 jpeg_start_compress(&jpeg->cinfo, FALSE);
258 return (JPEGBITS *) jpeg;
261 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
263 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
266 jpeg_write_scanlines(&jpeg->cinfo, data, n);
270 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
272 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
275 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
277 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
280 jpeg_finish_compress(&jpeg->cinfo);
281 jpeg_destroy_compress(&jpeg->cinfo);
286 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
291 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
292 U8 *scanline = (U8*)rfx_alloc(3 * width);
293 for (y = 0; y < height; y++) {
295 for (x = 0; x < width; x++) {
296 scanline[p++] = bitmap[width * y + x].r;
297 scanline[p++] = bitmap[width * y + x].g;
298 scanline[p++] = bitmap[width * y + x].b;
300 swf_SetJPEGBitsLine(jpeg, scanline);
303 swf_SetJPEGBitsFinish(jpeg);
306 void swf_GetJPEGSize(char *fname, int *width, int *height)
308 struct jpeg_decompress_struct cinfo;
309 struct jpeg_error_mgr jerr;
313 cinfo.err = jpeg_std_error(&jerr);
314 jpeg_create_decompress(&cinfo);
315 if ((fi = fopen(fname, "rb")) == NULL) {
316 fprintf(stderr, "rfxswf: file open error\n");
319 jpeg_stdio_src(&cinfo, fi);
320 jpeg_read_header(&cinfo, TRUE);
321 *width = cinfo.image_width;
322 *height = cinfo.image_height;
323 jpeg_destroy_decompress(&cinfo);
327 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
329 struct jpeg_decompress_struct cinfo;
330 struct jpeg_error_mgr jerr;
335 cinfo.err = jpeg_std_error(&jerr);
336 jpeg_create_decompress(&cinfo);
338 if ((f = fopen(fname, "rb")) == NULL) {
339 fprintf(stderr, "rfxswf: file open error\n");
343 jpeg_stdio_src(&cinfo, f);
344 jpeg_read_header(&cinfo, TRUE);
345 jpeg_start_decompress(&cinfo);
348 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
350 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
355 if (cinfo.out_color_space == JCS_GRAYSCALE) {
356 for (y = 0; y < cinfo.output_height; y++) {
358 jpeg_read_scanlines(&cinfo, &js, 1);
359 for (x = cinfo.output_width - 1; x >= 0; x--) {
360 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
362 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
364 } else if (cinfo.out_color_space == JCS_RGB) {
365 for (y = 0; y < cinfo.output_height; y++) {
366 jpeg_read_scanlines(&cinfo, &js, 1);
367 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
369 } else if (cinfo.out_color_space == JCS_YCCK) {
371 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
373 } else if (cinfo.out_color_space == JCS_YCbCr) {
374 for (y = 0; y < cinfo.output_height; y++) {
376 for (x = 0; x < cinfo.output_width; x++) {
377 int y = js[x * 3 + 0];
378 int u = js[x * 3 + 1];
379 int v = js[x * 3 + 1];
380 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
382 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
383 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
386 } else if (cinfo.out_color_space == JCS_CMYK) {
387 for (y = 0; y < cinfo.output_height; y++) {
389 jpeg_read_scanlines(&cinfo, &js, 1);
390 /* This routine seems to work for now-
391 It's a mixture of 3 different
392 CMYK->RGB conversion routines I found in the
393 web. (which all produced garbage)
394 I'm happily accepting suggestions. (mk) */
395 for (x = 0; x < cinfo.output_width; x++) {
396 int white = 255 - js[x * 4 + 3];
397 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
398 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
399 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
401 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
407 swf_SetJPEGBitsFinish(out);
408 jpeg_finish_decompress(&cinfo);
414 typedef struct _JPEGFILEMGR {
415 struct jpeg_destination_mgr mgr;
417 struct jpeg_compress_struct* cinfo;
418 struct jpeg_error_mgr* jerr;
422 static void file_init_destination(j_compress_ptr cinfo)
424 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
425 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
427 fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
430 fprintf(stderr, "Out of memory!\n");
434 dmgr->next_output_byte = fmgr->buffer;
435 dmgr->free_in_buffer = OUTBUFFER_SIZE;
438 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
440 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
441 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
444 fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
446 dmgr->next_output_byte = fmgr->buffer;
447 dmgr->free_in_buffer = OUTBUFFER_SIZE;
451 static void file_term_destination(j_compress_ptr cinfo)
453 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
454 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
457 fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
459 rfx_free(fmgr->buffer);
461 dmgr->free_in_buffer = 0;
462 dmgr->next_output_byte = 0;
465 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
468 struct jpeg_compress_struct cinfo;
469 struct jpeg_error_mgr jerr;
470 unsigned char*data2 = 0;
473 FILE*fi = fopen(filename, "wb");
476 sprintf(buf, "rfxswf: Couldn't create %s", filename);
480 data2 = (unsigned char *)rfx_calloc(width*3);
482 memset(&cinfo, 0, sizeof(cinfo));
483 memset(&jerr, 0, sizeof(jerr));
484 memset(&fmgr, 0, sizeof(fmgr));
485 cinfo.err = jpeg_std_error(&jerr);
486 jpeg_create_compress(&cinfo);
488 fmgr.mgr.init_destination = file_init_destination;
489 fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
490 fmgr.mgr.term_destination = file_term_destination;
494 cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
498 cinfo.image_width = width;
499 cinfo.image_height = height;
500 cinfo.input_components = 3;
501 cinfo.in_color_space = JCS_RGB;
502 jpeg_set_defaults(&cinfo);
503 cinfo.dct_method = JDCT_IFAST;
504 jpeg_set_quality(&cinfo,quality,TRUE);
506 //jpeg_write_tables(&cinfo);
507 //jpeg_suppress_tables(&cinfo, TRUE);
508 jpeg_start_compress(&cinfo, FALSE);
510 for(y=0;y<height;y++) {
512 RGBA*src = &pixels[y*width];
513 for(x=0;x<width;x++) {
514 data2[x*3+0] = src[x].r;
515 data2[x*3+1] = src[x].g;
516 data2[x*3+2] = src[x].b;
518 jpeg_write_scanlines(&cinfo, &data2, 1);
521 jpeg_finish_compress(&cinfo);
522 jpeg_destroy_compress(&cinfo);
527 /* jpeg_source_mgr functions */
528 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
530 TAG *tag = (TAG *) cinfo->client_data;
531 if (tag->id == ST_DEFINEBITSJPEG3) {
532 swf_SetTagPos(tag, 6);
534 swf_SetTagPos(tag, 2);
536 cinfo->src->bytes_in_buffer = 0;
538 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
540 TAG *tag = (TAG *) cinfo->client_data;
541 if (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) {
547 if (tag->pos >= tag->len) {
548 cinfo->src->next_input_byte = 0;
549 cinfo->src->bytes_in_buffer = 0;
552 cinfo->src->next_input_byte = &tag->data[tag->pos];
553 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
557 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
559 TAG *tag = (TAG *) cinfo->client_data;
560 cinfo->src->next_input_byte = 0;
561 cinfo->src->bytes_in_buffer = 0;
564 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
566 return jpeg_resync_to_restart(cinfo, desired);
568 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
570 TAG *tag = (TAG *) cinfo->client_data;
572 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
574 struct jpeg_decompress_struct cinfo;
575 struct jpeg_error_mgr jerr;
576 struct jpeg_source_mgr mgr;
584 if (tag->id == ST_DEFINEBITSJPEG) {
585 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
588 if (tag->id == ST_DEFINEBITSJPEG3) {
590 offset = swf_GetU32(tag);
591 oldtaglen = tag->len;
594 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
599 cinfo.err = jpeg_std_error(&jerr);
600 jpeg_create_decompress(&cinfo);
602 cinfo.client_data = (void *) tag;
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;
611 jpeg_read_header(&cinfo, TRUE);
612 *width = cinfo.image_width;
613 *height = cinfo.image_height;
615 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
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;
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];
634 jpeg_finish_decompress(&cinfo);
636 jpeg_destroy_decompress(&cinfo);
640 uLongf datalen = cinfo.output_width*cinfo.output_height;
641 U8* alphadata = (U8*)rfx_alloc(datalen);
643 tag->len = oldtaglen;
644 swf_SetTagPos(tag, 6+offset);
645 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
647 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
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];
654 for(x=0;x<cinfo.output_width;x++) {
655 line[x].a = aline[x];
664 #endif // HAVE_JPEGLIB
666 // Lossless compression texture based on zlib
670 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
672 U8 *data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
674 zs->avail_out = OUTBUFFER_SIZE;
676 int status = deflate(zs, Z_NO_FLUSH);
678 if (status != Z_OK) {
679 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
684 if (zs->next_out != data) {
685 swf_SetBlock(t, data, zs->next_out - data);
687 zs->avail_out = OUTBUFFER_SIZE;
690 if (zs->avail_in == 0)
700 int status = deflate(zs, Z_FINISH);
701 if (status != Z_OK && status != Z_STREAM_END) {
702 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
707 if (zs->next_out != data) {
708 swf_SetBlock(t, data, zs->next_out - data);
710 zs->avail_out = OUTBUFFER_SIZE;
713 if (status == Z_STREAM_END)
721 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
726 switch (bitmap_flags) {
728 return swf_SetLosslessBitsIndexed(t, width, height, (U8*)bitmap, NULL, 256);
730 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
736 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
740 swf_SetU8(t, bitmap_flags);
741 swf_SetU16(t, width);
742 swf_SetU16(t, height);
747 memset(&zs, 0x00, sizeof(z_stream));
751 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
752 zs.avail_in = bps * height;
753 zs.next_in = (Bytef *)bitmap;
755 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
760 res = -3; // zlib error
765 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
768 int bps = BYTES_PER_SCANLINE(width);
771 if (!pal) // create default palette for grayscale images
774 pal = (RGBA*)rfx_alloc(256 * sizeof(RGBA));
775 for (i = 0; i < 256; i++) {
776 pal[i].r = pal[i].g = pal[i].b = i;
782 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
783 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
785 return -1; // parameter error
788 swf_SetU8(t, BMF_8BIT);
789 swf_SetU16(t, width);
790 swf_SetU16(t, height);
791 swf_SetU8(t, ncolors - 1); // number of pal entries
796 memset(&zs, 0x00, sizeof(z_stream));
800 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
801 U8 *zpal; // compress palette
802 if ((zpal = (U8*)rfx_alloc(ncolors * 4))) {
806 /* be careful with ST_DEFINEBITSLOSSLESS2, because
807 the Flash player produces great bugs if you use too many
808 alpha colors in your palette. The only sensible result that
809 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
810 make transparent parts in sprites. That's the cause why alpha
811 handling is implemented in lossless routines of rfxswf.
813 Indeed: I haven't understood yet how flash player handles
814 alpha values different from 0 and 0xff in lossless bitmaps...
817 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
819 for (i = 0; i < ncolors; i++) {
826 zs.avail_in = 4 * ncolors;
828 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
835 zs.avail_in = 3 * ncolors;
840 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
845 zs.avail_in = (bps * height * sizeof(U8));
847 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
854 res = -2; // memory error
856 res = -3; // zlib error
865 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
867 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
870 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
872 int num = width*height;
875 data[t].r = ((int)data[t].r*data[t].a)/255;
876 data[t].g = ((int)data[t].g*data[t].a)/255;
877 data[t].b = ((int)data[t].b*data[t].a)/255;
881 /* expects mem to be non-premultiplied */
882 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
884 int hasalpha = swf_ImageHasAlpha(data, width, height);
887 tag->id = ST_DEFINEBITSLOSSLESS;
889 tag->id = ST_DEFINEBITSLOSSLESS2;
890 swf_PreMultiplyAlpha(data, width, height);
892 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
893 if(num>1 && num<=256) {
894 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
895 int width2 = BYTES_PER_SCANLINE(width);
896 U8*data2 = (U8*)malloc(width2*height);
897 int len = width*height;
900 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
901 for(y=0;y<height;y++) {
902 RGBA*src = &data[width*y];
903 U8*dest = &data2[width2*y];
904 for(x=0;x<width;x++) {
907 if(*(U32*)&col == *(U32*)&palette[r]) {
913 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
914 col.r, col.g, col.b, col.a, num);
919 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
923 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
927 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
929 int id, format, height, width, pos;
930 uLongf datalen, datalen2;
935 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
940 if (tag->id != ST_DEFINEBITSLOSSLESS &&
941 tag->id != ST_DEFINEBITSLOSSLESS2) {
942 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
946 swf_SetTagPos(tag, 0);
947 id = swf_GetU16(tag);
948 format = swf_GetU8(tag);
955 if (format != 3 && format != 5) {
958 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
961 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
965 *dwidth = width = swf_GetU16(tag);
966 *dheight = height = swf_GetU16(tag);
968 dest = (RGBA*)rfx_alloc(sizeof(RGBA) * width * height);
971 cols = swf_GetU8(tag) + 1;
976 datalen = (width * height * bpp / 8 + cols * 8);
981 data = (U8*)rfx_alloc(datalen);
983 uncompress(data, &datalen, &tag->data[tag->pos],
984 tag->len - tag->pos);
985 } while (error == Z_BUF_ERROR);
987 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
993 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
994 for (t = 0; t < cols; t++) {
995 palette[t].r = data[pos++];
996 palette[t].g = data[pos++];
997 palette[t].b = data[pos++];
999 palette[t].a = data[pos++];
1006 for (y = 0; y < height; y++) {
1007 int srcwidth = width * (bpp / 8);
1010 // 32 bit to 24 bit "conversion"
1011 for (x = 0; x < width; x++) {
1012 dest[pos2].r = data[pos + 1];
1013 dest[pos2].g = data[pos + 2];
1014 dest[pos2].b = data[pos + 3];
1017 pos += 4; //ignore padding byte
1020 for (x = 0; x < width; x++) {
1021 /* remove premultiplication */
1022 int alpha = data[pos+0];
1024 alpha = 0xff0000/alpha;
1025 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1026 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1027 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1028 dest[pos2].a = data[pos + 0]; //alpha
1034 for (x = 0; x < srcwidth; x++) {
1035 dest[pos2] = palette[data[pos++]];
1039 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1049 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1051 /* expects bitmap to be non-premultiplied */
1052 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1062 swf_SetU32(tag, 0); //placeholder
1063 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1064 U8 *scanline = (U8*)rfx_alloc(3 * width);
1065 for (y = 0; y < height; y++) {
1067 for (x = 0; x < width; x++) {
1068 //int ia = bitmap[width*y+x].a;
1070 // /* remove premultiplication */
1071 // ia = 0xff0000/ia;
1073 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1074 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1075 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1076 scanline[p++] = bitmap[width * y + x].r;
1077 scanline[p++] = bitmap[width * y + x].g;
1078 scanline[p++] = bitmap[width * y + x].b;
1080 swf_SetJPEGBitsLine(jpeg, scanline);
1083 swf_SetJPEGBitsFinish(jpeg);
1084 PUT32(&tag->data[pos], tag->len - pos - 4);
1086 data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
1087 memset(&zs, 0x00, sizeof(z_stream));
1089 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1090 fprintf(stderr, "rfxswf: zlib compression failed");
1095 zs.avail_out = OUTBUFFER_SIZE;
1097 scanline = (U8*)rfx_alloc(width);
1098 for (y = 0; y < height; y++) {
1100 for (x = 0; x < width; x++) {
1101 scanline[p++] = bitmap[width * y + x].a;
1103 zs.avail_in = width;
1104 zs.next_in = scanline;
1107 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1108 fprintf(stderr, "rfxswf: zlib compression failed");
1111 if (zs.next_out != data) {
1112 swf_SetBlock(tag, data, zs.next_out - data);
1114 zs.avail_out = OUTBUFFER_SIZE;
1125 int ret = deflate(&zs, Z_FINISH);
1126 if (ret != Z_OK && ret != Z_STREAM_END) {
1127 fprintf(stderr, "rfxswf: zlib compression failed");
1130 if (zs.next_out != data) {
1131 swf_SetBlock(tag, data, zs.next_out - data);
1133 zs.avail_out = OUTBUFFER_SIZE;
1135 if (ret == Z_STREAM_END) {
1145 /* expects mem to be non-premultiplied */
1146 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1148 TAG *tag1 = 0, *tag2 = 0;
1149 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1151 /* try lossless image */
1152 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1153 swf_SetU16(tag1, bitid);
1154 swf_SetLosslessImage(tag1, mem, width, height);
1156 /* try jpeg image */
1158 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1159 swf_SetU16(tag2, bitid);
1160 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1162 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1163 swf_SetU16(tag2, bitid);
1164 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1167 if(quality>100 || (tag1 && tag1->len < tag2->len)) {
1168 /* use the zlib version- it's smaller */
1170 if(tag) tag->next = tag1;
1172 swf_DeleteTag(tag2);
1174 /* use the jpeg version- it's smaller */
1176 if(tag) tag->next = tag2;
1178 swf_DeleteTag(tag1);
1185 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1189 swf_SetTagPos(tag, 2); // id is 2 bytes
1191 if (tag->id == ST_DEFINEBITSJPEG ||
1192 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1194 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1196 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1200 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1201 tag->id == ST_DEFINEBITSLOSSLESS2) {
1203 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1205 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1209 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1210 swf_TagGetName(tag));
1214 #undef OUTBUFFER_SIZE
1217 void swf_RemoveJPEGTables(SWF * swf)
1219 TAG *tag = swf->firstTag;
1220 TAG *tables_tag = 0;
1222 if (tag->id == ST_JPEGTABLES) {
1231 tag = swf->firstTag;
1233 if (tag->id == ST_DEFINEBITSJPEG) {
1235 void *data = rfx_alloc(len);
1236 swf_GetBlock(tag, (U8*)data, tag->len);
1237 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1238 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1239 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1240 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1245 if (swf->firstTag == tables_tag)
1246 swf->firstTag = tables_tag->next;
1247 swf_DeleteTag(tables_tag);
1250 typedef struct scale_lookup {
1252 unsigned int weight;
1255 typedef struct rgba_int {
1256 unsigned int r,g,b,a;
1259 static int bicubic = 0;
1261 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1263 scale_lookup_t*lookupx = (scale_lookup_t*)malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1264 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1265 double fx = ((double)width)/((double)newwidth);
1268 scale_lookup_t*p_x = lookupx;
1270 if(newwidth<=width) {
1271 for(x=0;x<newwidth;x++) {
1272 double ex = px + fx;
1273 int fromx = (int)px;
1275 double rem = fromx+1-px;
1276 int i = (int)(256/fx);
1277 int xweight = (int)(rem*256/fx);
1281 if(tox>=width) tox = width-1;
1282 for(xx=fromx;xx<=tox;xx++) {
1283 if(xx==fromx && xx==tox) p_x->weight = 256;
1284 else if(xx==fromx) p_x->weight = xweight;
1285 else if(xx==tox) p_x->weight = 256-w;
1286 else p_x->weight = i;
1294 for(x=0;x<newwidth;x++) {
1296 int ix2 = ((int)px)+1;
1298 if(ix2>=width) ix2=width-1;
1302 p_x[0].weight = (int)(256*(1-r));
1304 p_x[1].weight = 256-p_x[0].weight;
1310 lblockx[newwidth] = p_x;
1314 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1317 int len = width*height;
1319 U32* img = (U32*)data;
1320 U32 color1 = img[0];
1322 for(t=1;t<len;t++) {
1323 if(img[t] != color1) {
1328 *(U32*)&colors[0] = color1;
1329 *(U32*)&colors[1] = color2;
1330 for(t=0;t<len;t++) {
1331 if(img[t] == color1) {
1334 img[t] = 0xffffffff;
1339 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1342 int len = width*height;
1344 for(t=0;t<len;t++) {
1346 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1347 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1348 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1349 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1353 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1357 scale_lookup_t *p, **lblockx,**lblocky;
1360 RGBA monochrome_colors[2];
1362 if(newwidth<1 || newheight<1)
1365 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1367 encodeMonochromeImage(data, width, height, monochrome_colors);
1370 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1371 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1373 lblockx = make_scale_lookup(width, newwidth);
1374 lblocky = make_scale_lookup(height, newheight);
1376 for(p=lblocky[0];p<lblocky[newheight];p++)
1379 for(y=0;y<newheight;y++) {
1380 RGBA*destline = &newdata[y*newwidth];
1382 /* create lookup table for y */
1383 rgba_int_t*l = tmpline;
1384 scale_lookup_t*p_y,*p_x;
1385 memset(tmpline, 0, width*sizeof(rgba_int_t));
1386 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1387 RGBA*line = &data[p_y->pos];
1389 int weight = p_y->weight;
1390 for(x=0;x<width;x++) {
1391 tmpline[x].r += line[x].r*weight;
1392 tmpline[x].g += line[x].g*weight;
1393 tmpline[x].b += line[x].b*weight;
1394 tmpline[x].a += line[x].a*weight;
1398 /* process x direction */
1400 for(x=0;x<newwidth;x++) {
1401 unsigned int r=0,g=0,b=0,a=0;
1402 scale_lookup_t*p_x_to = lblockx[x+1];
1404 rgba_int_t* col = &tmpline[p_x->pos];
1405 unsigned int weight = p_x->weight;
1411 } while (p_x<p_x_to);
1413 destline->r = r >> 16;
1414 destline->g = g >> 16;
1415 destline->b = b >> 16;
1416 destline->a = a >> 16;
1423 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);