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 */
1187 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1188 tag1->len = 0x7fffffff;
1190 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1191 swf_SetU16(tag1, bitid);
1192 swf_SetLosslessImage(tag1, mem, width, height);
1195 #if defined(HAVE_JPEGLIB)
1196 /* try jpeg image */
1198 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1199 swf_SetU16(tag2, bitid);
1200 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1202 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1203 swf_SetU16(tag2, bitid);
1204 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1208 if(quality>100 || !tag2 || (tag1 && tag1->len < tag2->len)) {
1209 /* use the zlib version- it's smaller */
1211 if(tag) tag->next = tag1;
1213 swf_DeleteTag(0, tag2);
1215 /* use the jpeg version- it's smaller */
1217 if(tag) tag->next = tag2;
1219 swf_DeleteTag(0, tag1);
1224 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1228 swf_SetTagPos(tag, 2); // id is 2 bytes
1230 if (tag->id == ST_DEFINEBITSJPEG ||
1231 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1233 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1235 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1239 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1240 tag->id == ST_DEFINEBITSLOSSLESS2) {
1242 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1244 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1248 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1249 swf_TagGetName(tag));
1253 #undef OUTBUFFER_SIZE
1256 void swf_RemoveJPEGTables(SWF * swf)
1258 TAG *tag = swf->firstTag;
1259 TAG *tables_tag = 0;
1261 if (tag->id == ST_JPEGTABLES) {
1270 tag = swf->firstTag;
1272 if (tag->id == ST_DEFINEBITSJPEG) {
1274 void *data = rfx_alloc(len);
1275 swf_GetBlock(tag, (U8*)data, tag->len);
1276 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1277 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1278 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1279 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1284 if (swf->firstTag == tables_tag)
1285 swf->firstTag = tables_tag->next;
1286 swf_DeleteTag(swf, tables_tag);
1289 typedef struct scale_lookup {
1291 unsigned int weight;
1294 typedef struct rgba_int {
1295 unsigned int r,g,b,a;
1298 static int bicubic = 0;
1300 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1302 scale_lookup_t*lookupx = (scale_lookup_t*)malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1303 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1304 double fx = ((double)width)/((double)newwidth);
1307 scale_lookup_t*p_x = lookupx;
1309 if(newwidth<=width) {
1310 for(x=0;x<newwidth;x++) {
1311 double ex = px + fx;
1312 int fromx = (int)px;
1314 double rem = fromx+1-px;
1315 int i = (int)(256/fx);
1316 int xweight = (int)(rem*256/fx);
1320 if(tox>=width) tox = width-1;
1321 for(xx=fromx;xx<=tox;xx++) {
1322 if(xx==fromx && xx==tox) p_x->weight = 256;
1323 else if(xx==fromx) p_x->weight = xweight;
1324 else if(xx==tox) p_x->weight = 256-w;
1325 else p_x->weight = i;
1333 for(x=0;x<newwidth;x++) {
1335 int ix2 = ((int)px)+1;
1337 if(ix2>=width) ix2=width-1;
1341 p_x[0].weight = (int)(256*(1-r));
1343 p_x[1].weight = 256-p_x[0].weight;
1349 lblockx[newwidth] = p_x;
1353 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1356 int len = width*height;
1358 U32* img = (U32*)data;
1359 U32 color1 = img[0];
1361 for(t=1;t<len;t++) {
1362 if(img[t] != color1) {
1367 *(U32*)&colors[0] = color1;
1368 *(U32*)&colors[1] = color2;
1369 for(t=0;t<len;t++) {
1370 if(img[t] == color1) {
1373 img[t] = 0xffffffff;
1378 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1381 int len = width*height;
1383 for(t=0;t<len;t++) {
1385 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1386 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1387 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1388 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1392 static void blurImage(RGBA*src, int width, int height, int r)
1394 int e = 2; // r times e is the sampling interval
1395 double*gauss = (double*)malloc(r*e*sizeof(double));
1398 for(x=0;x<r*e;x++) {
1399 double t = (x - r*e/2.0)/r;
1400 gauss[x] = exp(-0.5*t*t);
1403 int*weights = (int*)malloc(r*e*sizeof(int));
1404 for(x=0;x<r*e;x++) {
1405 weights[x] = (int)(gauss[x]*65536.0001/sum);
1409 RGBA*tmp = malloc(sizeof(RGBA)*width*height);
1412 for(y=0;y<height;y++) {
1413 RGBA*s = &src[y*width];
1414 RGBA*d = &tmp[y*width];
1415 for(x=0;x<range;x++) {
1418 for(x=range;x<width-range;x++) {
1425 for(xx=x-range;xx<x+range;xx++) {
1426 r += s[xx].r * f[0];
1427 g += s[xx].g * f[0];
1428 b += s[xx].b * f[0];
1429 a += s[xx].a * f[0];
1437 for(x=width-range;x<width;x++) {
1442 for(x=0;x<width;x++) {
1446 for(y=0;y<range;y++) {
1450 for(y=range;y<height-range;y++) {
1456 int cy,cyy=yy-range*width;
1457 for(cy=y-range;cy<y+range;cy++) {
1458 r += s[cyy].r * f[0];
1459 g += s[cyy].g * f[0];
1460 b += s[cyy].b * f[0];
1461 a += s[cyy].a * f[0];
1471 for(y=0;y<range;y++) {
1483 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1487 scale_lookup_t *p, **lblockx,**lblocky;
1490 RGBA monochrome_colors[2];
1492 if(newwidth<1 || newheight<1)
1495 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1497 encodeMonochromeImage(data, width, height, monochrome_colors);
1498 int r1 = width / newwidth;
1499 int r2 = height / newheight;
1500 int r = r1<r2?r1:r2;
1502 /* high-resolution monochrome images are usually dithered, so
1503 low-pass filter them first to get rid of any moire patterns */
1504 blurImage(data, width, height, r+1);
1508 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1509 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1511 lblockx = make_scale_lookup(width, newwidth);
1512 lblocky = make_scale_lookup(height, newheight);
1514 for(p=lblocky[0];p<lblocky[newheight];p++)
1517 for(y=0;y<newheight;y++) {
1518 RGBA*destline = &newdata[y*newwidth];
1520 /* create lookup table for y */
1521 rgba_int_t*l = tmpline;
1522 scale_lookup_t*p_y,*p_x;
1523 memset(tmpline, 0, width*sizeof(rgba_int_t));
1524 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1525 RGBA*line = &data[p_y->pos];
1527 int weight = p_y->weight;
1528 for(x=0;x<width;x++) {
1529 tmpline[x].r += line[x].r*weight;
1530 tmpline[x].g += line[x].g*weight;
1531 tmpline[x].b += line[x].b*weight;
1532 tmpline[x].a += line[x].a*weight;
1536 /* process x direction */
1538 for(x=0;x<newwidth;x++) {
1539 unsigned int r=0,g=0,b=0,a=0;
1540 scale_lookup_t*p_x_to = lblockx[x+1];
1542 rgba_int_t* col = &tmpline[p_x->pos];
1543 unsigned int weight = p_x->weight;
1549 } while (p_x<p_x_to);
1551 destline->r = r >> 16;
1552 destline->g = g >> 16;
1553 destline->b = b >> 16;
1554 destline->a = a >> 16;
1561 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);