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 /* FIXME: we're destroying the callers data here */
891 swf_PreMultiplyAlpha(data, width, height);
893 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
894 if(num>1 && num<=256) {
895 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
896 int width2 = BYTES_PER_SCANLINE(width);
897 U8*data2 = (U8*)malloc(width2*height);
898 int len = width*height;
901 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
902 for(y=0;y<height;y++) {
903 RGBA*src = &data[width*y];
904 U8*dest = &data2[width2*y];
905 for(x=0;x<width;x++) {
908 if(*(U32*)&col == *(U32*)&palette[r]) {
914 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
915 col.r, col.g, col.b, col.a, num);
920 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
924 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
928 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
930 int id, format, height, width, pos;
931 uLongf datalen, datalen2;
936 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
941 if (tag->id != ST_DEFINEBITSLOSSLESS &&
942 tag->id != ST_DEFINEBITSLOSSLESS2) {
943 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
947 swf_SetTagPos(tag, 0);
948 id = swf_GetU16(tag);
949 format = swf_GetU8(tag);
956 if (format != 3 && format != 5) {
959 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
962 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
966 *dwidth = width = swf_GetU16(tag);
967 *dheight = height = swf_GetU16(tag);
969 dest = (RGBA*)rfx_alloc(sizeof(RGBA) * width * height);
972 cols = swf_GetU8(tag) + 1;
977 datalen = (width * height * bpp / 8 + cols * 8);
982 data = (U8*)rfx_alloc(datalen);
984 uncompress(data, &datalen, &tag->data[tag->pos],
985 tag->len - tag->pos);
986 } while (error == Z_BUF_ERROR);
988 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
994 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
995 for (t = 0; t < cols; t++) {
996 palette[t].r = data[pos++];
997 palette[t].g = data[pos++];
998 palette[t].b = data[pos++];
1000 palette[t].a = data[pos++];
1007 for (y = 0; y < height; y++) {
1008 int srcwidth = width * (bpp / 8);
1011 // 32 bit to 24 bit "conversion"
1012 for (x = 0; x < width; x++) {
1013 dest[pos2].r = data[pos + 1];
1014 dest[pos2].g = data[pos + 2];
1015 dest[pos2].b = data[pos + 3];
1018 pos += 4; //ignore padding byte
1021 for (x = 0; x < width; x++) {
1022 /* remove premultiplication */
1023 int alpha = data[pos+0];
1025 alpha = 0xff0000/alpha;
1026 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1027 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1028 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1029 dest[pos2].a = data[pos + 0]; //alpha
1035 for (x = 0; x < srcwidth; x++) {
1036 dest[pos2] = palette[data[pos++]];
1040 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1050 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1052 /* expects bitmap to be non-premultiplied */
1053 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1063 swf_SetU32(tag, 0); //placeholder
1064 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1065 U8 *scanline = (U8*)rfx_alloc(3 * width);
1066 for (y = 0; y < height; y++) {
1068 for (x = 0; x < width; x++) {
1069 //int ia = bitmap[width*y+x].a;
1071 // /* remove premultiplication */
1072 // ia = 0xff0000/ia;
1074 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1075 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1076 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1077 scanline[p++] = bitmap[width * y + x].r;
1078 scanline[p++] = bitmap[width * y + x].g;
1079 scanline[p++] = bitmap[width * y + x].b;
1081 swf_SetJPEGBitsLine(jpeg, scanline);
1084 swf_SetJPEGBitsFinish(jpeg);
1085 PUT32(&tag->data[pos], tag->len - pos - 4);
1087 data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
1088 memset(&zs, 0x00, sizeof(z_stream));
1090 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1091 fprintf(stderr, "rfxswf: zlib compression failed");
1096 zs.avail_out = OUTBUFFER_SIZE;
1098 scanline = (U8*)rfx_alloc(width);
1099 for (y = 0; y < height; y++) {
1101 for (x = 0; x < width; x++) {
1102 scanline[p++] = bitmap[width * y + x].a;
1104 zs.avail_in = width;
1105 zs.next_in = scanline;
1108 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1109 fprintf(stderr, "rfxswf: zlib compression failed");
1112 if (zs.next_out != data) {
1113 swf_SetBlock(tag, data, zs.next_out - data);
1115 zs.avail_out = OUTBUFFER_SIZE;
1126 int ret = deflate(&zs, Z_FINISH);
1127 if (ret != Z_OK && ret != Z_STREAM_END) {
1128 fprintf(stderr, "rfxswf: zlib compression failed");
1131 if (zs.next_out != data) {
1132 swf_SetBlock(tag, data, zs.next_out - data);
1134 zs.avail_out = OUTBUFFER_SIZE;
1136 if (ret == Z_STREAM_END) {
1147 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1149 fprintf(stderr, "Error: swftools compiled without jpeglib\n");
1156 /* expects mem to be non-premultiplied */
1157 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1159 TAG *tag1 = 0, *tag2 = 0;
1160 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1162 /* try lossless image */
1165 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1166 tag1->len = 0x7fffffff;
1168 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1169 swf_SetU16(tag1, bitid);
1170 swf_SetLosslessImage(tag1, mem, width, height);
1173 #if defined(HAVE_JPEGLIB)
1174 /* try jpeg image. Notice that if (and only if) we tried the lossless compression
1175 above, the data will now be premultiplied with alpha. */
1177 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1178 swf_SetU16(tag2, bitid);
1179 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1181 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1182 swf_SetU16(tag2, bitid);
1183 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1187 if(quality>100 || !tag2 || (tag1 && tag1->len < tag2->len)) {
1188 /* use the zlib version- it's smaller */
1190 if(tag) tag->next = tag1;
1192 swf_DeleteTag(0, tag2);
1194 /* use the jpeg version- it's smaller */
1196 if(tag) tag->next = tag2;
1198 swf_DeleteTag(0, tag1);
1203 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1207 swf_SetTagPos(tag, 2); // id is 2 bytes
1209 if (tag->id == ST_DEFINEBITSJPEG ||
1210 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1212 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1214 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1218 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1219 tag->id == ST_DEFINEBITSLOSSLESS2) {
1221 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1223 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1227 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1228 swf_TagGetName(tag));
1232 #undef OUTBUFFER_SIZE
1235 void swf_RemoveJPEGTables(SWF * swf)
1237 TAG *tag = swf->firstTag;
1238 TAG *tables_tag = 0;
1240 if (tag->id == ST_JPEGTABLES) {
1249 tag = swf->firstTag;
1251 if (tag->id == ST_DEFINEBITSJPEG) {
1253 void *data = rfx_alloc(len);
1254 swf_GetBlock(tag, (U8*)data, tag->len);
1255 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1256 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1257 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1258 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1263 if (swf->firstTag == tables_tag)
1264 swf->firstTag = tables_tag->next;
1265 swf_DeleteTag(swf, tables_tag);