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->pos + 4 <= tag->len &&
565 tag->data[tag->pos + 0] == 0xff &&
566 tag->data[tag->pos + 1] == 0xd9 &&
567 tag->data[tag->pos + 2] == 0xff &&
568 tag->data[tag->pos + 3] == 0xd8) {
571 if (tag->pos >= tag->len) {
572 cinfo->src->next_input_byte = 0;
573 cinfo->src->bytes_in_buffer = 0;
576 cinfo->src->next_input_byte = &tag->data[tag->pos];
577 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
581 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
583 TAG *tag = (TAG *) cinfo->client_data;
584 cinfo->src->next_input_byte = 0;
585 cinfo->src->bytes_in_buffer = 0;
588 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
590 return jpeg_resync_to_restart(cinfo, desired);
592 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
594 TAG *tag = (TAG *) cinfo->client_data;
596 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
598 struct jpeg_decompress_struct cinfo;
599 struct jpeg_error_mgr jerr;
600 struct jpeg_source_mgr mgr;
608 if (tag->id == ST_DEFINEBITSJPEG) {
609 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
612 if (tag->id == ST_DEFINEBITSJPEG3) {
614 offset = swf_GetU32(tag);
615 oldtaglen = tag->len;
618 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
623 cinfo.err = jpeg_std_error(&jerr);
624 jpeg_create_decompress(&cinfo);
626 cinfo.client_data = (void *) tag;
628 cinfo.src->init_source = tag_init_source;
629 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
630 cinfo.src->skip_input_data = tag_skip_input_data;
631 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
632 cinfo.src->term_source = tag_term_source;
633 cinfo.out_color_space = JCS_RGB;
635 jpeg_read_header(&cinfo, TRUE);
636 *width = cinfo.image_width;
637 *height = cinfo.image_height;
639 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
641 jpeg_start_decompress(&cinfo);
642 for (y = 0; y < cinfo.output_height; y++) {
643 RGBA *line = &dest[y * cinfo.image_width];
644 U8 *to = (U8 *) line;
646 jpeg_read_scanlines(&cinfo, &to, 1);
647 for (x = cinfo.output_width - 1; x >= 0; --x) {
648 int r = to[x * 3 + 0];
649 int g = to[x * 3 + 1];
650 int b = to[x * 3 + 2];
658 jpeg_finish_decompress(&cinfo);
660 jpeg_destroy_decompress(&cinfo);
664 uLongf datalen = cinfo.output_width*cinfo.output_height;
665 U8* alphadata = (U8*)rfx_alloc(datalen);
667 tag->len = oldtaglen;
668 swf_SetTagPos(tag, 6+offset);
669 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
671 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
674 for(y=0;y<cinfo.output_height;y++) {
675 RGBA*line = &dest[y*cinfo.output_width];
676 U8*aline = &alphadata[y*cinfo.output_width];
678 for(x=0;x<cinfo.output_width;x++) {
679 line[x].a = aline[x];
688 #endif // HAVE_JPEGLIB
690 // Lossless compression texture based on zlib
694 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
696 U8 *data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
698 zs->avail_out = OUTBUFFER_SIZE;
700 int status = deflate(zs, Z_NO_FLUSH);
702 if (status != Z_OK) {
703 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
708 if (zs->next_out != data) {
709 swf_SetBlock(t, data, zs->next_out - data);
711 zs->avail_out = OUTBUFFER_SIZE;
714 if (zs->avail_in == 0)
724 int status = deflate(zs, Z_FINISH);
725 if (status != Z_OK && status != Z_STREAM_END) {
726 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
731 if (zs->next_out != data) {
732 swf_SetBlock(t, data, zs->next_out - data);
734 zs->avail_out = OUTBUFFER_SIZE;
737 if (status == Z_STREAM_END)
745 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
750 switch (bitmap_flags) {
752 return swf_SetLosslessBitsIndexed(t, width, height, (U8*)bitmap, NULL, 256);
754 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
760 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
764 swf_SetU8(t, bitmap_flags);
765 swf_SetU16(t, width);
766 swf_SetU16(t, height);
771 memset(&zs, 0x00, sizeof(z_stream));
775 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
776 zs.avail_in = bps * height;
777 zs.next_in = (Bytef *)bitmap;
779 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
784 res = -3; // zlib error
789 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
792 int bps = BYTES_PER_SCANLINE(width);
795 if (!pal) // create default palette for grayscale images
798 pal = (RGBA*)rfx_alloc(256 * sizeof(RGBA));
799 for (i = 0; i < 256; i++) {
800 pal[i].r = pal[i].g = pal[i].b = i;
806 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
807 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
809 return -1; // parameter error
812 swf_SetU8(t, BMF_8BIT);
813 swf_SetU16(t, width);
814 swf_SetU16(t, height);
815 swf_SetU8(t, ncolors - 1); // number of pal entries
820 memset(&zs, 0x00, sizeof(z_stream));
824 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
825 U8 *zpal; // compress palette
826 if ((zpal = (U8*)rfx_alloc(ncolors * 4))) {
830 /* be careful with ST_DEFINEBITSLOSSLESS2, because
831 the Flash player produces great bugs if you use too many
832 alpha colors in your palette. The only sensible result that
833 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
834 make transparent parts in sprites. That's the cause why alpha
835 handling is implemented in lossless routines of rfxswf.
837 Indeed: I haven't understood yet how flash player handles
838 alpha values different from 0 and 0xff in lossless bitmaps...
841 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
843 for (i = 0; i < ncolors; i++) {
850 zs.avail_in = 4 * ncolors;
852 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
859 zs.avail_in = 3 * ncolors;
864 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
869 zs.avail_in = (bps * height * sizeof(U8));
871 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
878 res = -2; // memory error
880 res = -3; // zlib error
889 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
891 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
894 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
896 int num = width*height;
899 data[t].r = ((int)data[t].r*data[t].a)/255;
900 data[t].g = ((int)data[t].g*data[t].a)/255;
901 data[t].b = ((int)data[t].b*data[t].a)/255;
905 /* expects mem to be non-premultiplied */
906 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
908 int hasalpha = swf_ImageHasAlpha(data, width, height);
911 tag->id = ST_DEFINEBITSLOSSLESS;
913 tag->id = ST_DEFINEBITSLOSSLESS2;
914 swf_PreMultiplyAlpha(data, width, height);
916 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
917 if(num>1 && num<=256) {
918 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
919 int width2 = BYTES_PER_SCANLINE(width);
920 U8*data2 = (U8*)malloc(width2*height);
921 int len = width*height;
924 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
925 for(y=0;y<height;y++) {
926 RGBA*src = &data[width*y];
927 U8*dest = &data2[width2*y];
928 for(x=0;x<width;x++) {
931 if(*(U32*)&col == *(U32*)&palette[r]) {
937 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
938 col.r, col.g, col.b, col.a, num);
943 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
947 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
951 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
953 int id, format, height, width, pos;
954 uLongf datalen, datalen2;
959 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
964 if (tag->id != ST_DEFINEBITSLOSSLESS &&
965 tag->id != ST_DEFINEBITSLOSSLESS2) {
966 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
970 swf_SetTagPos(tag, 0);
971 id = swf_GetU16(tag);
972 format = swf_GetU8(tag);
979 if (format != 3 && format != 5) {
982 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
985 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
989 *dwidth = width = swf_GetU16(tag);
990 *dheight = height = swf_GetU16(tag);
992 dest = (RGBA*)rfx_alloc(sizeof(RGBA) * width * height);
995 cols = swf_GetU8(tag) + 1;
1000 datalen = (width * height * bpp / 8 + cols * 8);
1005 data = (U8*)rfx_alloc(datalen);
1007 uncompress(data, &datalen, &tag->data[tag->pos],
1008 tag->len - tag->pos);
1009 } while (error == Z_BUF_ERROR);
1010 if (error != Z_OK) {
1011 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
1017 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
1018 for (t = 0; t < cols; t++) {
1019 palette[t].r = data[pos++];
1020 palette[t].g = data[pos++];
1021 palette[t].b = data[pos++];
1023 palette[t].a = data[pos++];
1030 for (y = 0; y < height; y++) {
1031 int srcwidth = width * (bpp / 8);
1034 // 32 bit to 24 bit "conversion"
1035 for (x = 0; x < width; x++) {
1036 dest[pos2].r = data[pos + 1];
1037 dest[pos2].g = data[pos + 2];
1038 dest[pos2].b = data[pos + 3];
1041 pos += 4; //ignore padding byte
1044 for (x = 0; x < width; x++) {
1045 /* remove premultiplication */
1046 int alpha = data[pos+0];
1048 alpha = 0xff0000/alpha;
1049 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1050 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1051 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1052 dest[pos2].a = data[pos + 0]; //alpha
1058 for (x = 0; x < srcwidth; x++) {
1059 dest[pos2] = palette[data[pos++]];
1063 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1073 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1075 /* expects bitmap to be non-premultiplied */
1076 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1086 swf_SetU32(tag, 0); //placeholder
1087 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1088 U8 *scanline = (U8*)rfx_alloc(3 * width);
1089 for (y = 0; y < height; y++) {
1091 for (x = 0; x < width; x++) {
1092 //int ia = bitmap[width*y+x].a;
1094 // /* remove premultiplication */
1095 // ia = 0xff0000/ia;
1097 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1098 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1099 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1100 scanline[p++] = bitmap[width * y + x].r;
1101 scanline[p++] = bitmap[width * y + x].g;
1102 scanline[p++] = bitmap[width * y + x].b;
1104 swf_SetJPEGBitsLine(jpeg, scanline);
1107 swf_SetJPEGBitsFinish(jpeg);
1108 PUT32(&tag->data[pos], tag->len - pos - 4);
1110 data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
1111 memset(&zs, 0x00, sizeof(z_stream));
1113 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1114 fprintf(stderr, "rfxswf: zlib compression failed");
1119 zs.avail_out = OUTBUFFER_SIZE;
1121 scanline = (U8*)rfx_alloc(width);
1122 for (y = 0; y < height; y++) {
1124 for (x = 0; x < width; x++) {
1125 scanline[p++] = bitmap[width * y + x].a;
1127 zs.avail_in = width;
1128 zs.next_in = scanline;
1131 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1132 fprintf(stderr, "rfxswf: zlib compression failed");
1135 if (zs.next_out != data) {
1136 swf_SetBlock(tag, data, zs.next_out - data);
1138 zs.avail_out = OUTBUFFER_SIZE;
1149 int ret = deflate(&zs, Z_FINISH);
1150 if (ret != Z_OK && ret != Z_STREAM_END) {
1151 fprintf(stderr, "rfxswf: zlib compression failed");
1154 if (zs.next_out != data) {
1155 swf_SetBlock(tag, data, zs.next_out - data);
1157 zs.avail_out = OUTBUFFER_SIZE;
1159 if (ret == Z_STREAM_END) {
1170 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1172 fprintf(stderr, "Error: swftools compiled without jpeglib\n");
1178 /* expects mem to be non-premultiplied */
1179 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1181 TAG *tag1 = 0, *tag2 = 0;
1182 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1184 /* try lossless image */
1185 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1186 swf_SetU16(tag1, bitid);
1187 swf_SetLosslessImage(tag1, mem, width, height);
1189 #if defined(HAVE_JPEGLIB)
1190 /* try jpeg image */
1192 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1193 swf_SetU16(tag2, bitid);
1194 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1196 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1197 swf_SetU16(tag2, bitid);
1198 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1202 if(quality>100 || !tag2 || (tag1 && tag1->len < tag2->len)) {
1203 /* use the zlib version- it's smaller */
1205 if(tag) tag->next = tag1;
1207 swf_DeleteTag(0, tag2);
1209 /* use the jpeg version- it's smaller */
1211 if(tag) tag->next = tag2;
1213 swf_DeleteTag(0, tag1);
1218 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1222 swf_SetTagPos(tag, 2); // id is 2 bytes
1224 if (tag->id == ST_DEFINEBITSJPEG ||
1225 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1227 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1229 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1233 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1234 tag->id == ST_DEFINEBITSLOSSLESS2) {
1236 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1238 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1242 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1243 swf_TagGetName(tag));
1247 #undef OUTBUFFER_SIZE
1250 void swf_RemoveJPEGTables(SWF * swf)
1252 TAG *tag = swf->firstTag;
1253 TAG *tables_tag = 0;
1255 if (tag->id == ST_JPEGTABLES) {
1264 tag = swf->firstTag;
1266 if (tag->id == ST_DEFINEBITSJPEG) {
1268 void *data = rfx_alloc(len);
1269 swf_GetBlock(tag, (U8*)data, tag->len);
1270 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1271 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1272 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1273 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1278 if (swf->firstTag == tables_tag)
1279 swf->firstTag = tables_tag->next;
1280 swf_DeleteTag(swf, tables_tag);
1283 typedef struct scale_lookup {
1285 unsigned int weight;
1288 typedef struct rgba_int {
1289 unsigned int r,g,b,a;
1292 static int bicubic = 0;
1294 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1296 scale_lookup_t*lookupx = (scale_lookup_t*)malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1297 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1298 double fx = ((double)width)/((double)newwidth);
1301 scale_lookup_t*p_x = lookupx;
1303 if(newwidth<=width) {
1304 for(x=0;x<newwidth;x++) {
1305 double ex = px + fx;
1306 int fromx = (int)px;
1308 double rem = fromx+1-px;
1309 int i = (int)(256/fx);
1310 int xweight = (int)(rem*256/fx);
1314 if(tox>=width) tox = width-1;
1315 for(xx=fromx;xx<=tox;xx++) {
1316 if(xx==fromx && xx==tox) p_x->weight = 256;
1317 else if(xx==fromx) p_x->weight = xweight;
1318 else if(xx==tox) p_x->weight = 256-w;
1319 else p_x->weight = i;
1327 for(x=0;x<newwidth;x++) {
1329 int ix2 = ((int)px)+1;
1331 if(ix2>=width) ix2=width-1;
1335 p_x[0].weight = (int)(256*(1-r));
1337 p_x[1].weight = 256-p_x[0].weight;
1343 lblockx[newwidth] = p_x;
1347 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1350 int len = width*height;
1352 U32* img = (U32*)data;
1353 U32 color1 = img[0];
1355 for(t=1;t<len;t++) {
1356 if(img[t] != color1) {
1361 *(U32*)&colors[0] = color1;
1362 *(U32*)&colors[1] = color2;
1363 for(t=0;t<len;t++) {
1364 if(img[t] == color1) {
1367 img[t] = 0xffffffff;
1372 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1375 int len = width*height;
1377 for(t=0;t<len;t++) {
1379 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1380 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1381 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1382 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1386 static void blurImage(RGBA*src, int width, int height, int r)
1388 int e = 2; // r times e is the sampling interval
1389 double*gauss = (double*)malloc(r*e*sizeof(double));
1392 for(x=0;x<r*e;x++) {
1393 double t = (x - r*e/2.0)/r;
1394 gauss[x] = exp(-0.5*t*t);
1397 int*weights = (int*)malloc(r*e*sizeof(int));
1398 for(x=0;x<r*e;x++) {
1399 weights[x] = (int)(gauss[x]*65536.0001/sum);
1403 RGBA*tmp = malloc(sizeof(RGBA)*width*height);
1406 for(y=0;y<height;y++) {
1407 RGBA*s = &src[y*width];
1408 RGBA*d = &tmp[y*width];
1409 for(x=0;x<range;x++) {
1412 for(x=range;x<width-range;x++) {
1419 for(xx=x-range;xx<x+range;xx++) {
1420 r += s[xx].r * f[0];
1421 g += s[xx].g * f[0];
1422 b += s[xx].b * f[0];
1423 a += s[xx].a * f[0];
1431 for(x=width-range;x<width;x++) {
1436 for(x=0;x<width;x++) {
1440 for(y=0;y<range;y++) {
1444 for(y=range;y<height-range;y++) {
1450 int cy,cyy=yy-range*width;
1451 for(cy=y-range;cy<y+range;cy++) {
1452 r += s[cyy].r * f[0];
1453 g += s[cyy].g * f[0];
1454 b += s[cyy].b * f[0];
1455 a += s[cyy].a * f[0];
1465 for(y=0;y<range;y++) {
1477 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1481 scale_lookup_t *p, **lblockx,**lblocky;
1484 RGBA monochrome_colors[2];
1486 if(newwidth<1 || newheight<1)
1489 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1491 encodeMonochromeImage(data, width, height, monochrome_colors);
1492 int r1 = width / newwidth;
1493 int r2 = height / newheight;
1494 int r = r1<r2?r1:r2;
1496 /* high-resolution monochrome images are usually dithered, so
1497 low-pass filter them first to get rid of any moire patterns */
1498 blurImage(data, width, height, r+1);
1502 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1503 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1505 lblockx = make_scale_lookup(width, newwidth);
1506 lblocky = make_scale_lookup(height, newheight);
1508 for(p=lblocky[0];p<lblocky[newheight];p++)
1511 for(y=0;y<newheight;y++) {
1512 RGBA*destline = &newdata[y*newwidth];
1514 /* create lookup table for y */
1515 rgba_int_t*l = tmpline;
1516 scale_lookup_t*p_y,*p_x;
1517 memset(tmpline, 0, width*sizeof(rgba_int_t));
1518 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1519 RGBA*line = &data[p_y->pos];
1521 int weight = p_y->weight;
1522 for(x=0;x<width;x++) {
1523 tmpline[x].r += line[x].r*weight;
1524 tmpline[x].g += line[x].g*weight;
1525 tmpline[x].b += line[x].b*weight;
1526 tmpline[x].a += line[x].a*weight;
1530 /* process x direction */
1532 for(x=0;x<newwidth;x++) {
1533 unsigned int r=0,g=0,b=0,a=0;
1534 scale_lookup_t*p_x_to = lblockx[x+1];
1536 rgba_int_t* col = &tmpline[p_x->pos];
1537 unsigned int weight = p_x->weight;
1543 } while (p_x<p_x_to);
1545 destline->r = r >> 16;
1546 destline->g = g >> 16;
1547 destline->b = b >> 16;
1548 destline->a = a >> 16;
1555 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);