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 */
27 #include "../../config.h"
44 #endif // HAVE_JPEGLIB
46 #include "../rfxswf.h"
48 #define OUTBUFFER_SIZE 0x8000
50 int swf_ImageHasAlpha(RGBA*img, int width, int height)
52 int len = width*height;
56 if(img[t].a >= 4 && img[t].a < 0xfc)
64 int swf_ImageGetNumberOfPaletteEntries2(RGBA*_img, int width, int height)
66 int len = width*height;
68 U32* img = (U32*)_img;
72 if(img[t] != color1) {
81 if(img[t] != color1 && img[t] != color2) {
88 /*int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
90 int len = width*height;
95 int palette_overflow = 0;
98 if(sizeof(RGBA)!=sizeof(U32))
99 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
101 lastcol32 = pal32[palsize++] = *(U32*)&img[0];
105 U32 col32 = *(U32*)&img[t];
109 for(i=0;i<palsize;i++) {
110 if(col32 == pal32[i])
115 palette_overflow = 1;
118 pal32[palsize++] = col32;
125 memcpy(palette, pal, palsize*sizeof(RGBA));
129 int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
131 int len = width*height;
136 int palette_overflow = 0;
139 pal = (U32*)malloc(65536*sizeof(U32));
141 memset(size, 0, sizeof(size));
143 if(sizeof(RGBA)!=sizeof(U32))
144 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
146 lastcol32 = (*(U32*)&img[0])^0xffffffff; // don't match
150 U32 col32 = *(U32*)&img[t];
155 if(col32 == lastcol32)
157 hash = (col32 >> 17) ^ col32;
158 hash ^= ((hash>>8) + 1) ^ hash;
162 cpal = &pal[hash*256];
163 for(i=0;i<csize;i++) {
169 palette_overflow = 1;
172 cpal[size[hash]++] = col32;
177 if(palette_overflow) {
186 U32* cpal = &pal[t*256];
188 palette[i++] = *(RGBA*)(&cpal[s]);
199 typedef struct _JPEGDESTMGR {
200 struct jpeg_destination_mgr mgr;
203 struct jpeg_compress_struct cinfo;
204 struct jpeg_error_mgr jerr;
205 } JPEGDESTMGR, *LPJPEGDESTMGR;
207 // Destination manager callbacks
209 static void RFXSWF_init_destination(j_compress_ptr cinfo)
211 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
212 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
213 dmgr->mgr.next_output_byte = dmgr->buffer;
214 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
217 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
219 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
220 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
221 dmgr->mgr.next_output_byte = dmgr->buffer;
222 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
226 static void RFXSWF_term_destination(j_compress_ptr cinfo)
228 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
229 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
230 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
231 rfx_free(dmgr->buffer);
232 dmgr->mgr.free_in_buffer = 0;
235 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
239 // redirect compression lib output to local SWF Tag structure
241 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
243 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
245 jpeg_create_compress(&jpeg->cinfo);
247 jpeg->mgr.init_destination = RFXSWF_init_destination;
248 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
249 jpeg->mgr.term_destination = RFXSWF_term_destination;
253 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
257 jpeg->cinfo.image_width = width;
258 jpeg->cinfo.image_height = height;
259 jpeg->cinfo.input_components = 3;
260 jpeg->cinfo.in_color_space = JCS_RGB;
262 jpeg_set_defaults(&jpeg->cinfo);
263 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
265 // write tables to SWF
267 jpeg_write_tables(&jpeg->cinfo);
269 // compess image to SWF
271 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
272 jpeg_start_compress(&jpeg->cinfo, FALSE);
274 return (JPEGBITS *) jpeg;
277 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
279 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
282 jpeg_write_scanlines(&jpeg->cinfo, data, n);
286 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
288 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
291 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
293 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
296 jpeg_finish_compress(&jpeg->cinfo);
297 jpeg_destroy_compress(&jpeg->cinfo);
302 #if defined(HAVE_JPEGLIB)
303 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
307 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
308 U8 *scanline = (U8*)rfx_alloc(3 * width);
309 for (y = 0; y < height; y++) {
311 for (x = 0; x < width; x++) {
312 scanline[p++] = bitmap[width * y + x].r;
313 scanline[p++] = bitmap[width * y + x].g;
314 scanline[p++] = bitmap[width * y + x].b;
316 swf_SetJPEGBitsLine(jpeg, scanline);
319 swf_SetJPEGBitsFinish(jpeg);
322 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
324 fprintf(stderr, "Error: swftools compiled without jpeglib\n");
329 void swf_GetJPEGSize(const char *fname, int *width, int *height)
331 struct jpeg_decompress_struct cinfo;
332 struct jpeg_error_mgr jerr;
336 cinfo.err = jpeg_std_error(&jerr);
337 jpeg_create_decompress(&cinfo);
338 if ((fi = fopen(fname, "rb")) == NULL) {
339 fprintf(stderr, "rfxswf: file open error\n");
342 jpeg_stdio_src(&cinfo, fi);
343 jpeg_read_header(&cinfo, TRUE);
344 *width = cinfo.image_width;
345 *height = cinfo.image_height;
346 jpeg_destroy_decompress(&cinfo);
350 int swf_SetJPEGBits(TAG * t, const char *fname, int quality)
352 struct jpeg_decompress_struct cinfo;
353 struct jpeg_error_mgr jerr;
358 cinfo.err = jpeg_std_error(&jerr);
359 jpeg_create_decompress(&cinfo);
361 if ((f = fopen(fname, "rb")) == NULL) {
362 fprintf(stderr, "rfxswf: file open error\n");
366 jpeg_stdio_src(&cinfo, f);
367 jpeg_read_header(&cinfo, TRUE);
368 jpeg_start_decompress(&cinfo);
371 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
373 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
378 if (cinfo.out_color_space == JCS_GRAYSCALE) {
379 for (y = 0; y < cinfo.output_height; y++) {
381 jpeg_read_scanlines(&cinfo, &js, 1);
382 for (x = cinfo.output_width - 1; x >= 0; x--) {
383 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
385 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
387 } else if (cinfo.out_color_space == JCS_RGB) {
388 for (y = 0; y < cinfo.output_height; y++) {
389 jpeg_read_scanlines(&cinfo, &js, 1);
390 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
392 } else if (cinfo.out_color_space == JCS_YCCK) {
394 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
396 } else if (cinfo.out_color_space == JCS_YCbCr) {
397 for (y = 0; y < cinfo.output_height; y++) {
399 for (x = 0; x < cinfo.output_width; x++) {
400 int y = js[x * 3 + 0];
401 int u = js[x * 3 + 1];
402 int v = js[x * 3 + 1];
403 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
405 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
406 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
409 } else if (cinfo.out_color_space == JCS_CMYK) {
410 for (y = 0; y < cinfo.output_height; y++) {
412 jpeg_read_scanlines(&cinfo, &js, 1);
413 /* This routine seems to work for now-
414 It's a mixture of 3 different
415 CMYK->RGB conversion routines I found in the
416 web. (which all produced garbage)
417 I'm happily accepting suggestions. (mk) */
418 for (x = 0; x < cinfo.output_width; x++) {
419 int white = 255 - js[x * 4 + 3];
420 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
421 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
422 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
424 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
430 swf_SetJPEGBitsFinish(out);
431 jpeg_finish_decompress(&cinfo);
437 typedef struct _JPEGFILEMGR {
438 struct jpeg_destination_mgr mgr;
440 struct jpeg_compress_struct* cinfo;
441 struct jpeg_error_mgr* jerr;
445 static void file_init_destination(j_compress_ptr cinfo)
447 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
448 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
450 fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
453 fprintf(stderr, "Out of memory!\n");
457 dmgr->next_output_byte = fmgr->buffer;
458 dmgr->free_in_buffer = OUTBUFFER_SIZE;
461 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
463 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
464 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
467 fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
469 dmgr->next_output_byte = fmgr->buffer;
470 dmgr->free_in_buffer = OUTBUFFER_SIZE;
474 static void file_term_destination(j_compress_ptr cinfo)
476 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
477 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
480 fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
482 rfx_free(fmgr->buffer);
484 dmgr->free_in_buffer = 0;
485 dmgr->next_output_byte = 0;
488 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
491 struct jpeg_compress_struct cinfo;
492 struct jpeg_error_mgr jerr;
493 unsigned char*data2 = 0;
496 FILE*fi = fopen(filename, "wb");
499 sprintf(buf, "rfxswf: Couldn't create %s", filename);
503 data2 = (unsigned char *)rfx_calloc(width*3);
505 memset(&cinfo, 0, sizeof(cinfo));
506 memset(&jerr, 0, sizeof(jerr));
507 memset(&fmgr, 0, sizeof(fmgr));
508 cinfo.err = jpeg_std_error(&jerr);
509 jpeg_create_compress(&cinfo);
511 fmgr.mgr.init_destination = file_init_destination;
512 fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
513 fmgr.mgr.term_destination = file_term_destination;
517 cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
521 cinfo.image_width = width;
522 cinfo.image_height = height;
523 cinfo.input_components = 3;
524 cinfo.in_color_space = JCS_RGB;
525 jpeg_set_defaults(&cinfo);
526 cinfo.dct_method = JDCT_IFAST;
527 jpeg_set_quality(&cinfo,quality,TRUE);
529 //jpeg_write_tables(&cinfo);
530 //jpeg_suppress_tables(&cinfo, TRUE);
531 jpeg_start_compress(&cinfo, FALSE);
533 for(y=0;y<height;y++) {
535 RGBA*src = &pixels[y*width];
536 for(x=0;x<width;x++) {
537 data2[x*3+0] = src[x].r;
538 data2[x*3+1] = src[x].g;
539 data2[x*3+2] = src[x].b;
541 jpeg_write_scanlines(&cinfo, &data2, 1);
544 jpeg_finish_compress(&cinfo);
545 jpeg_destroy_compress(&cinfo);
550 /* jpeg_source_mgr functions */
551 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
553 TAG *tag = (TAG *) cinfo->client_data;
554 if (tag->id == ST_DEFINEBITSJPEG3) {
555 swf_SetTagPos(tag, 6);
557 swf_SetTagPos(tag, 2);
559 cinfo->src->bytes_in_buffer = 0;
561 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
563 TAG *tag = (TAG *) cinfo->client_data;
564 if (tag->data[tag->pos + 0] == 0xff &&
565 tag->data[tag->pos + 1] == 0xd9 &&
566 tag->data[tag->pos + 2] == 0xff &&
567 tag->data[tag->pos + 3] == 0xd8) {
570 if (tag->pos >= tag->len) {
571 cinfo->src->next_input_byte = 0;
572 cinfo->src->bytes_in_buffer = 0;
575 cinfo->src->next_input_byte = &tag->data[tag->pos];
576 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
580 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
582 TAG *tag = (TAG *) cinfo->client_data;
583 cinfo->src->next_input_byte = 0;
584 cinfo->src->bytes_in_buffer = 0;
587 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
589 return jpeg_resync_to_restart(cinfo, desired);
591 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
593 TAG *tag = (TAG *) cinfo->client_data;
595 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
597 struct jpeg_decompress_struct cinfo;
598 struct jpeg_error_mgr jerr;
599 struct jpeg_source_mgr mgr;
607 if (tag->id == ST_DEFINEBITSJPEG) {
608 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
611 if (tag->id == ST_DEFINEBITSJPEG3) {
613 offset = swf_GetU32(tag);
614 oldtaglen = tag->len;
617 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
622 cinfo.err = jpeg_std_error(&jerr);
623 jpeg_create_decompress(&cinfo);
625 cinfo.client_data = (void *) tag;
627 cinfo.src->init_source = tag_init_source;
628 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
629 cinfo.src->skip_input_data = tag_skip_input_data;
630 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
631 cinfo.src->term_source = tag_term_source;
632 cinfo.out_color_space = JCS_RGB;
634 jpeg_read_header(&cinfo, TRUE);
635 *width = cinfo.image_width;
636 *height = cinfo.image_height;
638 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
640 jpeg_start_decompress(&cinfo);
641 for (y = 0; y < cinfo.output_height; y++) {
642 RGBA *line = &dest[y * cinfo.image_width];
643 U8 *to = (U8 *) line;
645 jpeg_read_scanlines(&cinfo, &to, 1);
646 for (x = cinfo.output_width - 1; x >= 0; --x) {
647 int r = to[x * 3 + 0];
648 int g = to[x * 3 + 1];
649 int b = to[x * 3 + 2];
657 jpeg_finish_decompress(&cinfo);
659 jpeg_destroy_decompress(&cinfo);
663 uLongf datalen = cinfo.output_width*cinfo.output_height;
664 U8* alphadata = (U8*)rfx_alloc(datalen);
666 tag->len = oldtaglen;
667 swf_SetTagPos(tag, 6+offset);
668 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
670 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
673 for(y=0;y<cinfo.output_height;y++) {
674 RGBA*line = &dest[y*cinfo.output_width];
675 U8*aline = &alphadata[y*cinfo.output_width];
677 for(x=0;x<cinfo.output_width;x++) {
678 line[x].a = aline[x];
687 #endif // HAVE_JPEGLIB
689 // Lossless compression texture based on zlib
693 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
695 U8 *data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
697 zs->avail_out = OUTBUFFER_SIZE;
699 int status = deflate(zs, Z_NO_FLUSH);
701 if (status != Z_OK) {
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 (zs->avail_in == 0)
723 int status = deflate(zs, Z_FINISH);
724 if (status != Z_OK && status != Z_STREAM_END) {
725 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
730 if (zs->next_out != data) {
731 swf_SetBlock(t, data, zs->next_out - data);
733 zs->avail_out = OUTBUFFER_SIZE;
736 if (status == Z_STREAM_END)
744 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
749 switch (bitmap_flags) {
751 return swf_SetLosslessBitsIndexed(t, width, height, (U8*)bitmap, NULL, 256);
753 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
759 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
763 swf_SetU8(t, bitmap_flags);
764 swf_SetU16(t, width);
765 swf_SetU16(t, height);
770 memset(&zs, 0x00, sizeof(z_stream));
774 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
775 zs.avail_in = bps * height;
776 zs.next_in = (Bytef *)bitmap;
778 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
783 res = -3; // zlib error
788 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
791 int bps = BYTES_PER_SCANLINE(width);
794 if (!pal) // create default palette for grayscale images
797 pal = (RGBA*)rfx_alloc(256 * sizeof(RGBA));
798 for (i = 0; i < 256; i++) {
799 pal[i].r = pal[i].g = pal[i].b = i;
805 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
806 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
808 return -1; // parameter error
811 swf_SetU8(t, BMF_8BIT);
812 swf_SetU16(t, width);
813 swf_SetU16(t, height);
814 swf_SetU8(t, ncolors - 1); // number of pal entries
819 memset(&zs, 0x00, sizeof(z_stream));
823 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
824 U8 *zpal; // compress palette
825 if ((zpal = (U8*)rfx_alloc(ncolors * 4))) {
829 /* be careful with ST_DEFINEBITSLOSSLESS2, because
830 the Flash player produces great bugs if you use too many
831 alpha colors in your palette. The only sensible result that
832 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
833 make transparent parts in sprites. That's the cause why alpha
834 handling is implemented in lossless routines of rfxswf.
836 Indeed: I haven't understood yet how flash player handles
837 alpha values different from 0 and 0xff in lossless bitmaps...
840 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
842 for (i = 0; i < ncolors; i++) {
849 zs.avail_in = 4 * ncolors;
851 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
858 zs.avail_in = 3 * ncolors;
863 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
868 zs.avail_in = (bps * height * sizeof(U8));
870 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
877 res = -2; // memory error
879 res = -3; // zlib error
888 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
890 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
893 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
895 int num = width*height;
898 data[t].r = ((int)data[t].r*data[t].a)/255;
899 data[t].g = ((int)data[t].g*data[t].a)/255;
900 data[t].b = ((int)data[t].b*data[t].a)/255;
904 /* expects mem to be non-premultiplied */
905 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
907 int hasalpha = swf_ImageHasAlpha(data, width, height);
910 tag->id = ST_DEFINEBITSLOSSLESS;
912 tag->id = ST_DEFINEBITSLOSSLESS2;
913 swf_PreMultiplyAlpha(data, width, height);
915 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
916 if(num>1 && num<=256) {
917 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
918 int width2 = BYTES_PER_SCANLINE(width);
919 U8*data2 = (U8*)malloc(width2*height);
920 int len = width*height;
923 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
924 for(y=0;y<height;y++) {
925 RGBA*src = &data[width*y];
926 U8*dest = &data2[width2*y];
927 for(x=0;x<width;x++) {
930 if(*(U32*)&col == *(U32*)&palette[r]) {
936 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
937 col.r, col.g, col.b, col.a, num);
942 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
946 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
950 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
952 int id, format, height, width, pos;
953 uLongf datalen, datalen2;
958 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
963 if (tag->id != ST_DEFINEBITSLOSSLESS &&
964 tag->id != ST_DEFINEBITSLOSSLESS2) {
965 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
969 swf_SetTagPos(tag, 0);
970 id = swf_GetU16(tag);
971 format = swf_GetU8(tag);
978 if (format != 3 && format != 5) {
981 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
984 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
988 *dwidth = width = swf_GetU16(tag);
989 *dheight = height = swf_GetU16(tag);
991 dest = (RGBA*)rfx_alloc(sizeof(RGBA) * width * height);
994 cols = swf_GetU8(tag) + 1;
999 datalen = (width * height * bpp / 8 + cols * 8);
1004 data = (U8*)rfx_alloc(datalen);
1006 uncompress(data, &datalen, &tag->data[tag->pos],
1007 tag->len - tag->pos);
1008 } while (error == Z_BUF_ERROR);
1009 if (error != Z_OK) {
1010 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
1016 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
1017 for (t = 0; t < cols; t++) {
1018 palette[t].r = data[pos++];
1019 palette[t].g = data[pos++];
1020 palette[t].b = data[pos++];
1022 palette[t].a = data[pos++];
1029 for (y = 0; y < height; y++) {
1030 int srcwidth = width * (bpp / 8);
1033 // 32 bit to 24 bit "conversion"
1034 for (x = 0; x < width; x++) {
1035 dest[pos2].r = data[pos + 1];
1036 dest[pos2].g = data[pos + 2];
1037 dest[pos2].b = data[pos + 3];
1040 pos += 4; //ignore padding byte
1043 for (x = 0; x < width; x++) {
1044 /* remove premultiplication */
1045 int alpha = data[pos+0];
1047 alpha = 0xff0000/alpha;
1048 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1049 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1050 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1051 dest[pos2].a = data[pos + 0]; //alpha
1057 for (x = 0; x < srcwidth; x++) {
1058 dest[pos2] = palette[data[pos++]];
1062 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1072 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1074 /* expects bitmap to be non-premultiplied */
1075 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1085 swf_SetU32(tag, 0); //placeholder
1086 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1087 U8 *scanline = (U8*)rfx_alloc(3 * width);
1088 for (y = 0; y < height; y++) {
1090 for (x = 0; x < width; x++) {
1091 //int ia = bitmap[width*y+x].a;
1093 // /* remove premultiplication */
1094 // ia = 0xff0000/ia;
1096 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1097 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1098 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1099 scanline[p++] = bitmap[width * y + x].r;
1100 scanline[p++] = bitmap[width * y + x].g;
1101 scanline[p++] = bitmap[width * y + x].b;
1103 swf_SetJPEGBitsLine(jpeg, scanline);
1106 swf_SetJPEGBitsFinish(jpeg);
1107 PUT32(&tag->data[pos], tag->len - pos - 4);
1109 data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
1110 memset(&zs, 0x00, sizeof(z_stream));
1112 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1113 fprintf(stderr, "rfxswf: zlib compression failed");
1118 zs.avail_out = OUTBUFFER_SIZE;
1120 scanline = (U8*)rfx_alloc(width);
1121 for (y = 0; y < height; y++) {
1123 for (x = 0; x < width; x++) {
1124 scanline[p++] = bitmap[width * y + x].a;
1126 zs.avail_in = width;
1127 zs.next_in = scanline;
1130 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1131 fprintf(stderr, "rfxswf: zlib compression failed");
1134 if (zs.next_out != data) {
1135 swf_SetBlock(tag, data, zs.next_out - data);
1137 zs.avail_out = OUTBUFFER_SIZE;
1148 int ret = deflate(&zs, Z_FINISH);
1149 if (ret != Z_OK && ret != Z_STREAM_END) {
1150 fprintf(stderr, "rfxswf: zlib compression failed");
1153 if (zs.next_out != data) {
1154 swf_SetBlock(tag, data, zs.next_out - data);
1156 zs.avail_out = OUTBUFFER_SIZE;
1158 if (ret == Z_STREAM_END) {
1169 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1171 fprintf(stderr, "Error: swftools compiled without jpeglib\n");
1177 /* expects mem to be non-premultiplied */
1178 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1180 TAG *tag1 = 0, *tag2 = 0;
1181 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1183 /* try lossless image */
1184 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1185 swf_SetU16(tag1, bitid);
1186 swf_SetLosslessImage(tag1, mem, width, height);
1188 #if defined(HAVE_JPEGLIB)
1189 /* try jpeg image */
1191 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1192 swf_SetU16(tag2, bitid);
1193 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1195 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1196 swf_SetU16(tag2, bitid);
1197 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1201 if(quality>100 || !tag2 || (tag1 && tag1->len < tag2->len)) {
1202 /* use the zlib version- it's smaller */
1204 if(tag) tag->next = tag1;
1206 swf_DeleteTag(0, tag2);
1208 /* use the jpeg version- it's smaller */
1210 if(tag) tag->next = tag2;
1212 swf_DeleteTag(0, tag1);
1217 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1221 swf_SetTagPos(tag, 2); // id is 2 bytes
1223 if (tag->id == ST_DEFINEBITSJPEG ||
1224 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1226 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1228 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1232 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1233 tag->id == ST_DEFINEBITSLOSSLESS2) {
1235 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1237 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1241 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1242 swf_TagGetName(tag));
1246 #undef OUTBUFFER_SIZE
1249 void swf_RemoveJPEGTables(SWF * swf)
1251 TAG *tag = swf->firstTag;
1252 TAG *tables_tag = 0;
1254 if (tag->id == ST_JPEGTABLES) {
1263 tag = swf->firstTag;
1265 if (tag->id == ST_DEFINEBITSJPEG) {
1267 void *data = rfx_alloc(len);
1268 swf_GetBlock(tag, (U8*)data, tag->len);
1269 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1270 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1271 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1272 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1277 if (swf->firstTag == tables_tag)
1278 swf->firstTag = tables_tag->next;
1279 swf_DeleteTag(swf, tables_tag);
1282 typedef struct scale_lookup {
1284 unsigned int weight;
1287 typedef struct rgba_int {
1288 unsigned int r,g,b,a;
1291 static int bicubic = 0;
1293 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1295 scale_lookup_t*lookupx = (scale_lookup_t*)malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1296 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1297 double fx = ((double)width)/((double)newwidth);
1300 scale_lookup_t*p_x = lookupx;
1302 if(newwidth<=width) {
1303 for(x=0;x<newwidth;x++) {
1304 double ex = px + fx;
1305 int fromx = (int)px;
1307 double rem = fromx+1-px;
1308 int i = (int)(256/fx);
1309 int xweight = (int)(rem*256/fx);
1313 if(tox>=width) tox = width-1;
1314 for(xx=fromx;xx<=tox;xx++) {
1315 if(xx==fromx && xx==tox) p_x->weight = 256;
1316 else if(xx==fromx) p_x->weight = xweight;
1317 else if(xx==tox) p_x->weight = 256-w;
1318 else p_x->weight = i;
1326 for(x=0;x<newwidth;x++) {
1328 int ix2 = ((int)px)+1;
1330 if(ix2>=width) ix2=width-1;
1334 p_x[0].weight = (int)(256*(1-r));
1336 p_x[1].weight = 256-p_x[0].weight;
1342 lblockx[newwidth] = p_x;
1346 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1349 int len = width*height;
1351 U32* img = (U32*)data;
1352 U32 color1 = img[0];
1354 for(t=1;t<len;t++) {
1355 if(img[t] != color1) {
1360 *(U32*)&colors[0] = color1;
1361 *(U32*)&colors[1] = color2;
1362 for(t=0;t<len;t++) {
1363 if(img[t] == color1) {
1366 img[t] = 0xffffffff;
1371 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1374 int len = width*height;
1376 for(t=0;t<len;t++) {
1378 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1379 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1380 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1381 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1385 static void blurImage(RGBA*src, int width, int height, int r)
1387 int e = 2; // r times e is the sampling interval
1388 double*gauss = (double*)malloc(r*e*sizeof(double));
1391 for(x=0;x<r*e;x++) {
1392 double t = (x - r*e/2.0)/r;
1393 gauss[x] = exp(-0.5*t*t);
1396 int*weights = (int*)malloc(r*e*sizeof(int));
1397 for(x=0;x<r*e;x++) {
1398 weights[x] = (int)(gauss[x]*65536.0001/sum);
1402 RGBA*tmp = malloc(sizeof(RGBA)*width*height);
1405 for(y=0;y<height;y++) {
1406 RGBA*s = &src[y*width];
1407 RGBA*d = &tmp[y*width];
1408 for(x=0;x<range;x++) {
1411 for(x=range;x<width-range;x++) {
1418 for(xx=x-range;xx<x+range;xx++) {
1419 r += s[xx].r * f[0];
1420 g += s[xx].g * f[0];
1421 b += s[xx].b * f[0];
1422 a += s[xx].a * f[0];
1430 for(x=width-range;x<width;x++) {
1435 for(x=0;x<width;x++) {
1439 for(y=0;y<range;y++) {
1443 for(y=range;y<height-range;y++) {
1449 int cy,cyy=yy-range*width;
1450 for(cy=y-range;cy<y+range;cy++) {
1451 r += s[cyy].r * f[0];
1452 g += s[cyy].g * f[0];
1453 b += s[cyy].b * f[0];
1454 a += s[cyy].a * f[0];
1464 for(y=0;y<range;y++) {
1476 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1480 scale_lookup_t *p, **lblockx,**lblocky;
1483 RGBA monochrome_colors[2];
1485 if(newwidth<1 || newheight<1)
1488 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1490 encodeMonochromeImage(data, width, height, monochrome_colors);
1491 int r1 = width / newwidth;
1492 int r2 = height / newheight;
1493 int r = r1<r2?r1:r2;
1495 /* high-resolution monochrome images are usually dithered, so
1496 low-pass filter them first to get rid of any moire patterns */
1497 blurImage(data, width, height, r+1);
1501 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1502 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1504 lblockx = make_scale_lookup(width, newwidth);
1505 lblocky = make_scale_lookup(height, newheight);
1507 for(p=lblocky[0];p<lblocky[newheight];p++)
1510 for(y=0;y<newheight;y++) {
1511 RGBA*destline = &newdata[y*newwidth];
1513 /* create lookup table for y */
1514 rgba_int_t*l = tmpline;
1515 scale_lookup_t*p_y,*p_x;
1516 memset(tmpline, 0, width*sizeof(rgba_int_t));
1517 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1518 RGBA*line = &data[p_y->pos];
1520 int weight = p_y->weight;
1521 for(x=0;x<width;x++) {
1522 tmpline[x].r += line[x].r*weight;
1523 tmpline[x].g += line[x].g*weight;
1524 tmpline[x].b += line[x].b*weight;
1525 tmpline[x].a += line[x].a*weight;
1529 /* process x direction */
1531 for(x=0;x<newwidth;x++) {
1532 unsigned int r=0,g=0,b=0,a=0;
1533 scale_lookup_t*p_x_to = lblockx[x+1];
1535 rgba_int_t* col = &tmpline[p_x->pos];
1536 unsigned int weight = p_x->weight;
1542 } while (p_x<p_x_to);
1544 destline->r = r >> 16;
1545 destline->g = g >> 16;
1546 destline->b = b >> 16;
1547 destline->a = a >> 16;
1554 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);