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 for (y = 0; y < height; y++) {
293 U8 scanline[3 * width];
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);
302 swf_SetJPEGBitsFinish(jpeg);
305 void swf_GetJPEGSize(char *fname, int *width, int *height)
307 struct jpeg_decompress_struct cinfo;
308 struct jpeg_error_mgr jerr;
312 cinfo.err = jpeg_std_error(&jerr);
313 jpeg_create_decompress(&cinfo);
314 if ((fi = fopen(fname, "rb")) == NULL) {
315 fprintf(stderr, "rfxswf: file open error\n");
318 jpeg_stdio_src(&cinfo, fi);
319 jpeg_read_header(&cinfo, TRUE);
320 *width = cinfo.image_width;
321 *height = cinfo.image_height;
322 jpeg_destroy_decompress(&cinfo);
326 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
328 struct jpeg_decompress_struct cinfo;
329 struct jpeg_error_mgr jerr;
334 cinfo.err = jpeg_std_error(&jerr);
335 jpeg_create_decompress(&cinfo);
337 if ((f = fopen(fname, "rb")) == NULL) {
338 fprintf(stderr, "rfxswf: file open error\n");
342 jpeg_stdio_src(&cinfo, f);
343 jpeg_read_header(&cinfo, TRUE);
344 jpeg_start_decompress(&cinfo);
347 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
349 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
354 if (cinfo.out_color_space == JCS_GRAYSCALE) {
355 for (y = 0; y < cinfo.output_height; y++) {
357 jpeg_read_scanlines(&cinfo, &js, 1);
358 for (x = cinfo.output_width - 1; x >= 0; x--) {
359 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
361 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
363 } else if (cinfo.out_color_space == JCS_RGB) {
364 for (y = 0; y < cinfo.output_height; y++) {
365 jpeg_read_scanlines(&cinfo, &js, 1);
366 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
368 } else if (cinfo.out_color_space == JCS_YCCK) {
370 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
372 } else if (cinfo.out_color_space == JCS_YCbCr) {
373 for (y = 0; y < cinfo.output_height; y++) {
375 for (x = 0; x < cinfo.output_width; x++) {
376 int y = js[x * 3 + 0];
377 int u = js[x * 3 + 1];
378 int v = js[x * 3 + 1];
379 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
381 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
382 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
385 } else if (cinfo.out_color_space == JCS_CMYK) {
386 for (y = 0; y < cinfo.output_height; y++) {
388 jpeg_read_scanlines(&cinfo, &js, 1);
389 /* This routine seems to work for now-
390 It's a mixture of 3 different
391 CMYK->RGB conversion routines I found in the
392 web. (which all produced garbage)
393 I'm happily accepting suggestions. (mk) */
394 for (x = 0; x < cinfo.output_width; x++) {
395 int white = 255 - js[x * 4 + 3];
396 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
397 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
398 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
400 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
406 swf_SetJPEGBitsFinish(out);
407 jpeg_finish_decompress(&cinfo);
413 typedef struct _JPEGFILEMGR {
414 struct jpeg_destination_mgr mgr;
416 struct jpeg_compress_struct* cinfo;
417 struct jpeg_error_mgr* jerr;
421 static void file_init_destination(j_compress_ptr cinfo)
423 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
424 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
426 fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
429 fprintf(stderr, "Out of memory!\n");
433 dmgr->next_output_byte = fmgr->buffer;
434 dmgr->free_in_buffer = OUTBUFFER_SIZE;
437 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
439 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
440 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
443 fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
445 dmgr->next_output_byte = fmgr->buffer;
446 dmgr->free_in_buffer = OUTBUFFER_SIZE;
450 static void file_term_destination(j_compress_ptr cinfo)
452 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
453 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
456 fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
458 rfx_free(fmgr->buffer);
460 dmgr->free_in_buffer = 0;
461 dmgr->next_output_byte = 0;
464 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
467 struct jpeg_compress_struct cinfo;
468 struct jpeg_error_mgr jerr;
469 unsigned char*data2 = 0;
472 FILE*fi = fopen(filename, "wb");
475 sprintf(buf, "rfxswf: Couldn't create %s", filename);
479 data2 = (unsigned char *)rfx_calloc(width*3);
481 memset(&cinfo, 0, sizeof(cinfo));
482 memset(&jerr, 0, sizeof(jerr));
483 memset(&fmgr, 0, sizeof(fmgr));
484 cinfo.err = jpeg_std_error(&jerr);
485 jpeg_create_compress(&cinfo);
487 fmgr.mgr.init_destination = file_init_destination;
488 fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
489 fmgr.mgr.term_destination = file_term_destination;
493 cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
497 cinfo.image_width = width;
498 cinfo.image_height = height;
499 cinfo.input_components = 3;
500 cinfo.in_color_space = JCS_RGB;
501 jpeg_set_defaults(&cinfo);
502 cinfo.dct_method = JDCT_IFAST;
503 jpeg_set_quality(&cinfo,quality,TRUE);
505 //jpeg_write_tables(&cinfo);
506 //jpeg_suppress_tables(&cinfo, TRUE);
507 jpeg_start_compress(&cinfo, FALSE);
509 for(y=0;y<height;y++) {
511 RGBA*src = &pixels[y*width];
512 for(x=0;x<width;x++) {
513 data2[x*3+0] = src[x].r;
514 data2[x*3+1] = src[x].g;
515 data2[x*3+2] = src[x].b;
517 jpeg_write_scanlines(&cinfo, &data2, 1);
520 jpeg_finish_compress(&cinfo);
521 jpeg_destroy_compress(&cinfo);
526 /* jpeg_source_mgr functions */
527 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
529 TAG *tag = (TAG *) cinfo->client_data;
530 if (tag->id == ST_DEFINEBITSJPEG3) {
531 swf_SetTagPos(tag, 6);
533 swf_SetTagPos(tag, 2);
535 cinfo->src->bytes_in_buffer = 0;
537 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
539 TAG *tag = (TAG *) cinfo->client_data;
540 if (tag->data[tag->pos + 0] == 0xff &&
541 tag->data[tag->pos + 1] == 0xd9 &&
542 tag->data[tag->pos + 2] == 0xff &&
543 tag->data[tag->pos + 3] == 0xd8) {
546 if (tag->pos >= tag->len) {
547 cinfo->src->next_input_byte = 0;
548 cinfo->src->bytes_in_buffer = 0;
551 cinfo->src->next_input_byte = &tag->data[tag->pos];
552 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
556 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
558 TAG *tag = (TAG *) cinfo->client_data;
559 cinfo->src->next_input_byte = 0;
560 cinfo->src->bytes_in_buffer = 0;
563 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
565 return jpeg_resync_to_restart(cinfo, desired);
567 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
569 TAG *tag = (TAG *) cinfo->client_data;
571 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
573 struct jpeg_decompress_struct cinfo;
574 struct jpeg_error_mgr jerr;
575 struct jpeg_source_mgr mgr;
583 if (tag->id == ST_DEFINEBITSJPEG) {
584 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
587 if (tag->id == ST_DEFINEBITSJPEG3) {
589 offset = swf_GetU32(tag);
590 oldtaglen = tag->len;
593 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
598 cinfo.err = jpeg_std_error(&jerr);
599 jpeg_create_decompress(&cinfo);
601 cinfo.client_data = (void *) tag;
603 cinfo.src->init_source = tag_init_source;
604 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
605 cinfo.src->skip_input_data = tag_skip_input_data;
606 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
607 cinfo.src->term_source = tag_term_source;
608 cinfo.out_color_space = JCS_RGB;
610 jpeg_read_header(&cinfo, TRUE);
611 *width = cinfo.image_width;
612 *height = cinfo.image_height;
614 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
616 jpeg_start_decompress(&cinfo);
617 for (y = 0; y < cinfo.output_height; y++) {
618 RGBA *line = &dest[y * cinfo.image_width];
619 U8 *to = (U8 *) line;
621 jpeg_read_scanlines(&cinfo, &to, 1);
622 for (x = cinfo.output_width - 1; x >= 0; --x) {
623 int r = to[x * 3 + 0];
624 int g = to[x * 3 + 1];
625 int b = to[x * 3 + 2];
633 jpeg_finish_decompress(&cinfo);
635 jpeg_destroy_decompress(&cinfo);
639 uLongf datalen = cinfo.output_width*cinfo.output_height;
640 U8* alphadata = (U8*)rfx_alloc(datalen);
642 tag->len = oldtaglen;
643 swf_SetTagPos(tag, 6+offset);
644 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
646 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
649 for(y=0;y<cinfo.output_height;y++) {
650 RGBA*line = &dest[y*cinfo.output_width];
651 U8*aline = &alphadata[y*cinfo.output_width];
653 for(x=0;x<cinfo.output_width;x++) {
654 line[x].a = aline[x];
663 #endif // HAVE_JPEGLIB
665 // Lossless compression texture based on zlib
669 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
671 U8 *data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
673 zs->avail_out = OUTBUFFER_SIZE;
675 int status = deflate(zs, Z_NO_FLUSH);
677 if (status != Z_OK) {
678 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
683 if (zs->next_out != data) {
684 swf_SetBlock(t, data, zs->next_out - data);
686 zs->avail_out = OUTBUFFER_SIZE;
689 if (zs->avail_in == 0)
699 int status = deflate(zs, Z_FINISH);
700 if (status != Z_OK && status != Z_STREAM_END) {
701 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
706 if (zs->next_out != data) {
707 swf_SetBlock(t, data, zs->next_out - data);
709 zs->avail_out = OUTBUFFER_SIZE;
712 if (status == Z_STREAM_END)
720 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
725 switch (bitmap_flags) {
727 return swf_SetLosslessBitsIndexed(t, width, height, (U8*)bitmap, NULL, 256);
729 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
735 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
739 swf_SetU8(t, bitmap_flags);
740 swf_SetU16(t, width);
741 swf_SetU16(t, height);
746 memset(&zs, 0x00, sizeof(z_stream));
750 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
751 zs.avail_in = bps * height;
752 zs.next_in = (Bytef *)bitmap;
754 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
759 res = -3; // zlib error
764 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
767 int bps = BYTES_PER_SCANLINE(width);
770 if (!pal) // create default palette for grayscale images
773 pal = (RGBA*)rfx_alloc(256 * sizeof(RGBA));
774 for (i = 0; i < 256; i++) {
775 pal[i].r = pal[i].g = pal[i].b = i;
781 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
782 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
784 return -1; // parameter error
787 swf_SetU8(t, BMF_8BIT);
788 swf_SetU16(t, width);
789 swf_SetU16(t, height);
790 swf_SetU8(t, ncolors - 1); // number of pal entries
795 memset(&zs, 0x00, sizeof(z_stream));
799 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
800 U8 *zpal; // compress palette
801 if ((zpal = (U8*)rfx_alloc(ncolors * 4))) {
805 /* be careful with ST_DEFINEBITSLOSSLESS2, because
806 the Flash player produces great bugs if you use too many
807 alpha colors in your palette. The only sensible result that
808 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
809 make transparent parts in sprites. That's the cause why alpha
810 handling is implemented in lossless routines of rfxswf.
812 Indeed: I haven't understood yet how flash player handles
813 alpha values different from 0 and 0xff in lossless bitmaps...
816 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
818 for (i = 0; i < ncolors; i++) {
825 zs.avail_in = 4 * ncolors;
827 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
834 zs.avail_in = 3 * ncolors;
839 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
844 zs.avail_in = (bps * height * sizeof(U8));
846 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
853 res = -2; // memory error
855 res = -3; // zlib error
864 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
866 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
869 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
871 int num = width*height;
874 data[t].r = ((int)data[t].r*data[t].a)/255;
875 data[t].g = ((int)data[t].g*data[t].a)/255;
876 data[t].b = ((int)data[t].b*data[t].a)/255;
880 /* expects mem to be non-premultiplied */
881 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
883 int hasalpha = swf_ImageHasAlpha(data, width, height);
886 tag->id = ST_DEFINEBITSLOSSLESS;
888 tag->id = ST_DEFINEBITSLOSSLESS2;
889 swf_PreMultiplyAlpha(data, width, height);
891 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
892 if(num>1 && num<=256) {
893 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
894 int width2 = BYTES_PER_SCANLINE(width);
895 U8*data2 = (U8*)malloc(width2*height);
896 int len = width*height;
899 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
900 for(y=0;y<height;y++) {
901 RGBA*src = &data[width*y];
902 U8*dest = &data2[width2*y];
903 for(x=0;x<width;x++) {
906 if(*(U32*)&col == *(U32*)&palette[r]) {
912 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
913 col.r, col.g, col.b, col.a, num);
918 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
922 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
926 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
928 int id, format, height, width, pos;
929 uLongf datalen, datalen2;
934 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
939 if (tag->id != ST_DEFINEBITSLOSSLESS &&
940 tag->id != ST_DEFINEBITSLOSSLESS2) {
941 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
945 swf_SetTagPos(tag, 0);
946 id = swf_GetU16(tag);
947 format = swf_GetU8(tag);
954 if (format != 3 && format != 5) {
957 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
960 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
964 *dwidth = width = swf_GetU16(tag);
965 *dheight = height = swf_GetU16(tag);
967 dest = (RGBA*)rfx_alloc(sizeof(RGBA) * width * height);
970 cols = swf_GetU8(tag) + 1;
975 datalen = (width * height * bpp / 8 + cols * 8);
980 data = (U8*)rfx_alloc(datalen);
982 uncompress(data, &datalen, &tag->data[tag->pos],
983 tag->len - tag->pos);
984 } while (error == Z_BUF_ERROR);
986 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
992 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
993 for (t = 0; t < cols; t++) {
994 palette[t].r = data[pos++];
995 palette[t].g = data[pos++];
996 palette[t].b = data[pos++];
998 palette[t].a = data[pos++];
1005 for (y = 0; y < height; y++) {
1006 int srcwidth = width * (bpp / 8);
1009 // 32 bit to 24 bit "conversion"
1010 for (x = 0; x < width; x++) {
1011 dest[pos2].r = data[pos + 1];
1012 dest[pos2].g = data[pos + 2];
1013 dest[pos2].b = data[pos + 3];
1016 pos += 4; //ignore padding byte
1019 for (x = 0; x < width; x++) {
1020 /* remove premultiplication */
1021 int alpha = data[pos+0];
1023 alpha = 0xff0000/alpha;
1024 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1025 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1026 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1027 dest[pos2].a = data[pos + 0]; //alpha
1033 for (x = 0; x < srcwidth; x++) {
1034 dest[pos2] = palette[data[pos++]];
1038 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1048 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1050 /* expects bitmap to be non-premultiplied */
1051 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1061 swf_SetU32(tag, 0); //placeholder
1062 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1063 for (y = 0; y < height; y++) {
1064 U8 scanline[3 * width];
1066 for (x = 0; x < width; x++) {
1067 //int ia = bitmap[width*y+x].a;
1069 // /* remove premultiplication */
1070 // ia = 0xff0000/ia;
1072 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1073 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1074 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1075 scanline[p++] = bitmap[width * y + x].r;
1076 scanline[p++] = bitmap[width * y + x].g;
1077 scanline[p++] = bitmap[width * y + x].b;
1079 swf_SetJPEGBitsLine(jpeg, scanline);
1081 swf_SetJPEGBitsFinish(jpeg);
1082 PUT32(&tag->data[pos], tag->len - pos - 4);
1084 data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
1085 memset(&zs, 0x00, sizeof(z_stream));
1087 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1088 fprintf(stderr, "rfxswf: zlib compression failed");
1093 zs.avail_out = OUTBUFFER_SIZE;
1095 for (y = 0; y < height; y++) {
1098 for (x = 0; x < width; x++) {
1099 scanline[p++] = bitmap[width * y + x].a;
1101 zs.avail_in = width;
1102 zs.next_in = scanline;
1105 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1106 fprintf(stderr, "rfxswf: zlib compression failed");
1109 if (zs.next_out != data) {
1110 swf_SetBlock(tag, data, zs.next_out - data);
1112 zs.avail_out = OUTBUFFER_SIZE;
1121 int ret = deflate(&zs, Z_FINISH);
1122 if (ret != Z_OK && ret != Z_STREAM_END) {
1123 fprintf(stderr, "rfxswf: zlib compression failed");
1126 if (zs.next_out != data) {
1127 swf_SetBlock(tag, data, zs.next_out - data);
1129 zs.avail_out = OUTBUFFER_SIZE;
1131 if (ret == Z_STREAM_END) {
1141 /* expects mem to be non-premultiplied */
1142 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1144 TAG *tag1 = 0, *tag2 = 0;
1145 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1147 /* try lossless image */
1148 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1149 swf_SetU16(tag1, bitid);
1150 swf_SetLosslessImage(tag1, mem, width, height);
1152 /* try jpeg image */
1154 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1155 swf_SetU16(tag2, bitid);
1156 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1158 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1159 swf_SetU16(tag2, bitid);
1160 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1163 if(quality>100 || (tag1 && tag1->len < tag2->len)) {
1164 /* use the zlib version- it's smaller */
1166 if(tag) tag->next = tag1;
1168 swf_DeleteTag(tag2);
1170 /* use the jpeg version- it's smaller */
1172 if(tag) tag->next = tag2;
1174 swf_DeleteTag(tag1);
1181 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1185 swf_SetTagPos(tag, 2); // id is 2 bytes
1187 if (tag->id == ST_DEFINEBITSJPEG ||
1188 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1190 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1192 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1196 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1197 tag->id == ST_DEFINEBITSLOSSLESS2) {
1199 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1201 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1205 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1206 swf_TagGetName(tag));
1210 #undef OUTBUFFER_SIZE
1213 void swf_RemoveJPEGTables(SWF * swf)
1215 TAG *tag = swf->firstTag;
1216 TAG *tables_tag = 0;
1218 if (tag->id == ST_JPEGTABLES) {
1227 tag = swf->firstTag;
1229 if (tag->id == ST_DEFINEBITSJPEG) {
1231 void *data = rfx_alloc(len);
1232 swf_GetBlock(tag, (U8*)data, tag->len);
1233 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1234 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1235 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1236 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1241 if (swf->firstTag == tables_tag)
1242 swf->firstTag = tables_tag->next;
1243 swf_DeleteTag(tables_tag);
1246 typedef struct scale_lookup {
1248 unsigned int weight;
1251 typedef struct rgba_int {
1252 unsigned int r,g,b,a;
1255 static int bicubic = 0;
1257 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1259 scale_lookup_t*lookupx = (scale_lookup_t*)malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1260 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1261 double fx = ((double)width)/((double)newwidth);
1264 scale_lookup_t*p_x = lookupx;
1266 if(newwidth<=width) {
1267 for(x=0;x<newwidth;x++) {
1268 double ex = px + fx;
1269 int fromx = (int)px;
1271 double rem = fromx+1-px;
1272 int i = (int)(256/fx);
1273 int xweight = (int)(rem*256/fx);
1277 if(tox>=width) tox = width-1;
1278 for(xx=fromx;xx<=tox;xx++) {
1279 if(xx==fromx && xx==tox) p_x->weight = 256;
1280 else if(xx==fromx) p_x->weight = xweight;
1281 else if(xx==tox) p_x->weight = 256-w;
1282 else p_x->weight = i;
1290 for(x=0;x<newwidth;x++) {
1292 int ix2 = ((int)px)+1;
1294 if(ix2>=width) ix2=width-1;
1298 p_x[0].weight = (int)(256*(1-r));
1300 p_x[1].weight = 256-p_x[0].weight;
1306 lblockx[newwidth] = p_x;
1310 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1313 int len = width*height;
1315 U32* img = (U32*)data;
1316 U32 color1 = img[0];
1318 for(t=1;t<len;t++) {
1319 if(img[t] != color1) {
1324 *(U32*)&colors[0] = color1;
1325 *(U32*)&colors[1] = color2;
1326 for(t=0;t<len;t++) {
1327 if(img[t] == color1) {
1330 img[t] = 0xffffffff;
1335 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1338 int len = width*height;
1340 for(t=0;t<len;t++) {
1342 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1343 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1344 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1345 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1349 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1353 scale_lookup_t *p, **lblockx,**lblocky;
1356 RGBA monochrome_colors[2];
1358 if(newwidth<1 || newheight<1)
1361 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1363 encodeMonochromeImage(data, width, height, monochrome_colors);
1366 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1367 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1369 lblockx = make_scale_lookup(width, newwidth);
1370 lblocky = make_scale_lookup(height, newheight);
1372 for(p=lblocky[0];p<lblocky[newheight];p++)
1375 for(y=0;y<newheight;y++) {
1376 RGBA*destline = &newdata[y*newwidth];
1378 /* create lookup table for y */
1379 rgba_int_t*l = tmpline;
1380 scale_lookup_t*p_y,*p_x;
1381 memset(tmpline, 0, width*sizeof(rgba_int_t));
1382 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1383 RGBA*line = &data[p_y->pos];
1385 int weight = p_y->weight;
1386 for(x=0;x<width;x++) {
1387 tmpline[x].r += line[x].r*weight;
1388 tmpline[x].g += line[x].g*weight;
1389 tmpline[x].b += line[x].b*weight;
1390 tmpline[x].a += line[x].a*weight;
1394 /* process x direction */
1396 for(x=0;x<newwidth;x++) {
1397 unsigned int r=0,g=0,b=0,a=0;
1398 scale_lookup_t*p_x_to = lblockx[x+1];
1400 rgba_int_t* col = &tmpline[p_x->pos];
1401 unsigned int weight = p_x->weight;
1407 } while (p_x<p_x_to);
1409 destline->r = r >> 16;
1410 destline->g = g >> 16;
1411 destline->b = b >> 16;
1412 destline->a = a >> 16;
1419 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);