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_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
66 int len = width*height;
71 int palette_overflow = 0;
74 if(sizeof(RGBA)!=sizeof(U32))
75 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
77 lastcol32 = pal32[palsize++] = *(U32*)&img[0];
81 U32 col32 = *(U32*)&img[t];
85 for(i=0;i<palsize;i++) {
94 pal32[palsize++] = col32;
101 memcpy(palette, pal, palsize*sizeof(RGBA));
105 int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
107 int len = width*height;
112 int palette_overflow = 0;
115 pal = (U32*)malloc(65536*sizeof(U32));
117 memset(size, 0, sizeof(size));
119 if(sizeof(RGBA)!=sizeof(U32))
120 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
122 lastcol32 = (*(U32*)&img[0])^0xffffffff; // don't match
126 U32 col32 = *(U32*)&img[t];
131 if(col32 == lastcol32)
133 hash = (col32 >> 17) ^ col32;
134 hash ^= ((hash>>8) + 1) ^ hash;
138 cpal = &pal[hash*256];
139 for(i=0;i<csize;i++) {
145 palette_overflow = 1;
148 cpal[size[hash]++] = col32;
153 if(palette_overflow) {
162 U32* cpal = &pal[t*256];
164 palette[i++] = *(RGBA*)(&cpal[s]);
175 typedef struct _JPEGDESTMGR {
176 struct jpeg_destination_mgr mgr;
179 struct jpeg_compress_struct cinfo;
180 struct jpeg_error_mgr jerr;
181 } JPEGDESTMGR, *LPJPEGDESTMGR;
183 // Destination manager callbacks
185 static void RFXSWF_init_destination(j_compress_ptr cinfo)
187 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
188 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
189 dmgr->mgr.next_output_byte = dmgr->buffer;
190 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
193 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
195 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
196 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
197 dmgr->mgr.next_output_byte = dmgr->buffer;
198 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
202 static void RFXSWF_term_destination(j_compress_ptr cinfo)
204 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
205 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
206 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
207 rfx_free(dmgr->buffer);
208 dmgr->mgr.free_in_buffer = 0;
211 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
215 // redirect compression lib output to local SWF Tag structure
217 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
219 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
221 jpeg_create_compress(&jpeg->cinfo);
223 jpeg->mgr.init_destination = RFXSWF_init_destination;
224 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
225 jpeg->mgr.term_destination = RFXSWF_term_destination;
229 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
233 jpeg->cinfo.image_width = width;
234 jpeg->cinfo.image_height = height;
235 jpeg->cinfo.input_components = 3;
236 jpeg->cinfo.in_color_space = JCS_RGB;
238 jpeg_set_defaults(&jpeg->cinfo);
239 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
241 // write tables to SWF
243 jpeg_write_tables(&jpeg->cinfo);
245 // compess image to SWF
247 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
248 jpeg_start_compress(&jpeg->cinfo, FALSE);
250 return (JPEGBITS *) jpeg;
253 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
255 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
258 jpeg_write_scanlines(&jpeg->cinfo, data, n);
262 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
264 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
267 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
269 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
272 jpeg_finish_compress(&jpeg->cinfo);
273 jpeg_destroy_compress(&jpeg->cinfo);
278 #if defined(HAVE_JPEGLIB)
279 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
283 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
284 U8 *scanline = (U8*)rfx_alloc(3 * width);
285 for (y = 0; y < height; y++) {
287 for (x = 0; x < width; x++) {
288 scanline[p++] = bitmap[width * y + x].r;
289 scanline[p++] = bitmap[width * y + x].g;
290 scanline[p++] = bitmap[width * y + x].b;
292 swf_SetJPEGBitsLine(jpeg, scanline);
295 swf_SetJPEGBitsFinish(jpeg);
298 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
300 fprintf(stderr, "Error: swftools compiled without jpeglib\n");
305 void swf_GetJPEGSize(const 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, const 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->pos + 4 <= tag->len &&
541 tag->data[tag->pos + 0] == 0xff &&
542 tag->data[tag->pos + 1] == 0xd9 &&
543 tag->data[tag->pos + 2] == 0xff &&
544 tag->data[tag->pos + 3] == 0xd8) {
547 if (tag->pos >= tag->len) {
548 cinfo->src->next_input_byte = 0;
549 cinfo->src->bytes_in_buffer = 0;
552 cinfo->src->next_input_byte = &tag->data[tag->pos];
553 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
557 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
559 TAG *tag = (TAG *) cinfo->client_data;
560 cinfo->src->next_input_byte = 0;
561 cinfo->src->bytes_in_buffer = 0;
564 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
566 return jpeg_resync_to_restart(cinfo, desired);
568 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
570 TAG *tag = (TAG *) cinfo->client_data;
572 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
574 struct jpeg_decompress_struct cinfo;
575 struct jpeg_error_mgr jerr;
576 struct jpeg_source_mgr mgr;
584 if (tag->id == ST_DEFINEBITSJPEG) {
585 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
588 if (tag->id == ST_DEFINEBITSJPEG3) {
590 offset = swf_GetU32(tag);
591 oldtaglen = tag->len;
594 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
599 cinfo.err = jpeg_std_error(&jerr);
600 jpeg_create_decompress(&cinfo);
602 cinfo.client_data = (void *) tag;
604 cinfo.src->init_source = tag_init_source;
605 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
606 cinfo.src->skip_input_data = tag_skip_input_data;
607 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
608 cinfo.src->term_source = tag_term_source;
609 cinfo.out_color_space = JCS_RGB;
611 jpeg_read_header(&cinfo, TRUE);
612 *width = cinfo.image_width;
613 *height = cinfo.image_height;
615 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
617 jpeg_start_decompress(&cinfo);
618 for (y = 0; y < cinfo.output_height; y++) {
619 RGBA *line = &dest[y * cinfo.image_width];
620 U8 *to = (U8 *) line;
622 jpeg_read_scanlines(&cinfo, &to, 1);
623 for (x = cinfo.output_width - 1; x >= 0; --x) {
624 int r = to[x * 3 + 0];
625 int g = to[x * 3 + 1];
626 int b = to[x * 3 + 2];
634 jpeg_finish_decompress(&cinfo);
636 jpeg_destroy_decompress(&cinfo);
640 uLongf datalen = cinfo.output_width*cinfo.output_height;
641 U8* alphadata = (U8*)rfx_alloc(datalen);
643 tag->len = oldtaglen;
644 swf_SetTagPos(tag, 6+offset);
645 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
647 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
650 for(y=0;y<cinfo.output_height;y++) {
651 RGBA*line = &dest[y*cinfo.output_width];
652 U8*aline = &alphadata[y*cinfo.output_width];
654 for(x=0;x<cinfo.output_width;x++) {
655 line[x].a = aline[x];
664 #endif // HAVE_JPEGLIB
666 // Lossless compression texture based on zlib
670 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
672 U8 *data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
674 zs->avail_out = OUTBUFFER_SIZE;
676 int status = deflate(zs, Z_NO_FLUSH);
678 if (status != Z_OK) {
679 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
684 if (zs->next_out != data) {
685 swf_SetBlock(t, data, zs->next_out - data);
687 zs->avail_out = OUTBUFFER_SIZE;
690 if (zs->avail_in == 0)
700 int status = deflate(zs, Z_FINISH);
701 if (status != Z_OK && status != Z_STREAM_END) {
702 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
707 if (zs->next_out != data) {
708 swf_SetBlock(t, data, zs->next_out - data);
710 zs->avail_out = OUTBUFFER_SIZE;
713 if (status == Z_STREAM_END)
721 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
726 switch (bitmap_flags) {
728 return swf_SetLosslessBitsIndexed(t, width, height, (U8*)bitmap, NULL, 256);
730 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
736 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
740 swf_SetU8(t, bitmap_flags);
741 swf_SetU16(t, width);
742 swf_SetU16(t, height);
747 memset(&zs, 0x00, sizeof(z_stream));
751 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
752 zs.avail_in = bps * height;
753 zs.next_in = (Bytef *)bitmap;
755 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
760 res = -3; // zlib error
765 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
768 int bps = BYTES_PER_SCANLINE(width);
771 if (!pal) // create default palette for grayscale images
774 pal = (RGBA*)rfx_alloc(256 * sizeof(RGBA));
775 for (i = 0; i < 256; i++) {
776 pal[i].r = pal[i].g = pal[i].b = i;
782 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
783 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
785 return -1; // parameter error
788 swf_SetU8(t, BMF_8BIT);
789 swf_SetU16(t, width);
790 swf_SetU16(t, height);
791 swf_SetU8(t, ncolors - 1); // number of pal entries
796 memset(&zs, 0x00, sizeof(z_stream));
800 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
801 U8 *zpal; // compress palette
802 if ((zpal = (U8*)rfx_alloc(ncolors * 4))) {
806 /* be careful with ST_DEFINEBITSLOSSLESS2, because
807 the Flash player produces great bugs if you use too many
808 alpha colors in your palette. The only sensible result that
809 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
810 make transparent parts in sprites. That's the cause why alpha
811 handling is implemented in lossless routines of rfxswf.
813 Indeed: I haven't understood yet how flash player handles
814 alpha values different from 0 and 0xff in lossless bitmaps...
817 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
819 for (i = 0; i < ncolors; i++) {
826 zs.avail_in = 4 * ncolors;
828 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
835 zs.avail_in = 3 * ncolors;
840 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
845 zs.avail_in = (bps * height * sizeof(U8));
847 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
854 res = -2; // memory error
856 res = -3; // zlib error
865 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
867 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
870 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
872 int num = width*height;
875 data[t].r = ((int)data[t].r*data[t].a)/255;
876 data[t].g = ((int)data[t].g*data[t].a)/255;
877 data[t].b = ((int)data[t].b*data[t].a)/255;
881 /* expects mem to be non-premultiplied */
882 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
884 int hasalpha = swf_ImageHasAlpha(data, width, height);
887 tag->id = ST_DEFINEBITSLOSSLESS;
889 tag->id = ST_DEFINEBITSLOSSLESS2;
890 swf_PreMultiplyAlpha(data, width, height);
892 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
893 if(num>1 && num<=256) {
894 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
895 int width2 = BYTES_PER_SCANLINE(width);
896 U8*data2 = (U8*)malloc(width2*height);
897 int len = width*height;
900 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
901 for(y=0;y<height;y++) {
902 RGBA*src = &data[width*y];
903 U8*dest = &data2[width2*y];
904 for(x=0;x<width;x++) {
907 if(*(U32*)&col == *(U32*)&palette[r]) {
913 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
914 col.r, col.g, col.b, col.a, num);
919 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
923 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
927 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
929 int id, format, height, width, pos;
930 uLongf datalen, datalen2;
935 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
940 if (tag->id != ST_DEFINEBITSLOSSLESS &&
941 tag->id != ST_DEFINEBITSLOSSLESS2) {
942 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
946 swf_SetTagPos(tag, 0);
947 id = swf_GetU16(tag);
948 format = swf_GetU8(tag);
955 if (format != 3 && format != 5) {
958 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
961 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
965 *dwidth = width = swf_GetU16(tag);
966 *dheight = height = swf_GetU16(tag);
968 dest = (RGBA*)rfx_alloc(sizeof(RGBA) * width * height);
971 cols = swf_GetU8(tag) + 1;
976 datalen = (width * height * bpp / 8 + cols * 8);
981 data = (U8*)rfx_alloc(datalen);
983 uncompress(data, &datalen, &tag->data[tag->pos],
984 tag->len - tag->pos);
985 } while (error == Z_BUF_ERROR);
987 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
993 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
994 for (t = 0; t < cols; t++) {
995 palette[t].r = data[pos++];
996 palette[t].g = data[pos++];
997 palette[t].b = data[pos++];
999 palette[t].a = data[pos++];
1006 for (y = 0; y < height; y++) {
1007 int srcwidth = width * (bpp / 8);
1010 // 32 bit to 24 bit "conversion"
1011 for (x = 0; x < width; x++) {
1012 dest[pos2].r = data[pos + 1];
1013 dest[pos2].g = data[pos + 2];
1014 dest[pos2].b = data[pos + 3];
1017 pos += 4; //ignore padding byte
1020 for (x = 0; x < width; x++) {
1021 /* remove premultiplication */
1022 int alpha = data[pos+0];
1024 alpha = 0xff0000/alpha;
1025 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1026 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1027 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1028 dest[pos2].a = data[pos + 0]; //alpha
1034 for (x = 0; x < srcwidth; x++) {
1035 dest[pos2] = palette[data[pos++]];
1039 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1049 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1051 /* expects bitmap to be non-premultiplied */
1052 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1062 swf_SetU32(tag, 0); //placeholder
1063 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1064 U8 *scanline = (U8*)rfx_alloc(3 * width);
1065 for (y = 0; y < height; y++) {
1067 for (x = 0; x < width; x++) {
1068 //int ia = bitmap[width*y+x].a;
1070 // /* remove premultiplication */
1071 // ia = 0xff0000/ia;
1073 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1074 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1075 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1076 scanline[p++] = bitmap[width * y + x].r;
1077 scanline[p++] = bitmap[width * y + x].g;
1078 scanline[p++] = bitmap[width * y + x].b;
1080 swf_SetJPEGBitsLine(jpeg, scanline);
1083 swf_SetJPEGBitsFinish(jpeg);
1084 PUT32(&tag->data[pos], tag->len - pos - 4);
1086 data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
1087 memset(&zs, 0x00, sizeof(z_stream));
1089 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1090 fprintf(stderr, "rfxswf: zlib compression failed");
1095 zs.avail_out = OUTBUFFER_SIZE;
1097 scanline = (U8*)rfx_alloc(width);
1098 for (y = 0; y < height; y++) {
1100 for (x = 0; x < width; x++) {
1101 scanline[p++] = bitmap[width * y + x].a;
1103 zs.avail_in = width;
1104 zs.next_in = scanline;
1107 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1108 fprintf(stderr, "rfxswf: zlib compression failed");
1111 if (zs.next_out != data) {
1112 swf_SetBlock(tag, data, zs.next_out - data);
1114 zs.avail_out = OUTBUFFER_SIZE;
1125 int ret = deflate(&zs, Z_FINISH);
1126 if (ret != Z_OK && ret != Z_STREAM_END) {
1127 fprintf(stderr, "rfxswf: zlib compression failed");
1130 if (zs.next_out != data) {
1131 swf_SetBlock(tag, data, zs.next_out - data);
1133 zs.avail_out = OUTBUFFER_SIZE;
1135 if (ret == Z_STREAM_END) {
1146 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1148 fprintf(stderr, "Error: swftools compiled without jpeglib\n");
1154 /* expects mem to be non-premultiplied */
1155 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1157 TAG *tag1 = 0, *tag2 = 0;
1158 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1160 /* try lossless image */
1163 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1164 tag1->len = 0x7fffffff;
1166 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1167 swf_SetU16(tag1, bitid);
1168 swf_SetLosslessImage(tag1, mem, width, height);
1171 #if defined(HAVE_JPEGLIB)
1172 /* try jpeg image */
1174 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1175 swf_SetU16(tag2, bitid);
1176 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1178 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1179 swf_SetU16(tag2, bitid);
1180 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1184 if(quality>100 || !tag2 || (tag1 && tag1->len < tag2->len)) {
1185 /* use the zlib version- it's smaller */
1187 if(tag) tag->next = tag1;
1189 swf_DeleteTag(0, tag2);
1191 /* use the jpeg version- it's smaller */
1193 if(tag) tag->next = tag2;
1195 swf_DeleteTag(0, tag1);
1200 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1204 swf_SetTagPos(tag, 2); // id is 2 bytes
1206 if (tag->id == ST_DEFINEBITSJPEG ||
1207 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1209 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1211 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1215 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1216 tag->id == ST_DEFINEBITSLOSSLESS2) {
1218 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1220 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1224 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1225 swf_TagGetName(tag));
1229 #undef OUTBUFFER_SIZE
1232 void swf_RemoveJPEGTables(SWF * swf)
1234 TAG *tag = swf->firstTag;
1235 TAG *tables_tag = 0;
1237 if (tag->id == ST_JPEGTABLES) {
1246 tag = swf->firstTag;
1248 if (tag->id == ST_DEFINEBITSJPEG) {
1250 void *data = rfx_alloc(len);
1251 swf_GetBlock(tag, (U8*)data, tag->len);
1252 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1253 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1254 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1255 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1260 if (swf->firstTag == tables_tag)
1261 swf->firstTag = tables_tag->next;
1262 swf_DeleteTag(swf, tables_tag);