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 */
24 #define OUTBUFFER_SIZE 0x8000
26 int swf_ImageHasAlpha(RGBA*img, int width, int height)
28 int len = width*height;
32 if(img[t].a >= 4 && img[t].a < 0xfc)
40 int swf_ImageGetNumberOfPaletteEntries2(RGBA*_img, int width, int height)
42 int len = width*height;
44 U32* img = (U32*)_img;
48 if(img[t] != color1) {
57 if(img[t] != color1 && img[t] != color2) {
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 = 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);
277 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
282 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
283 for (y = 0; y < height; y++) {
284 U8 scanline[3 * width];
286 for (x = 0; x < width; x++) {
287 scanline[p++] = bitmap[width * y + x].r;
288 scanline[p++] = bitmap[width * y + x].g;
289 scanline[p++] = bitmap[width * y + x].b;
291 swf_SetJPEGBitsLine(jpeg, scanline);
293 swf_SetJPEGBitsFinish(jpeg);
296 void swf_GetJPEGSize(char *fname, int *width, int *height)
298 struct jpeg_decompress_struct cinfo;
299 struct jpeg_error_mgr jerr;
303 cinfo.err = jpeg_std_error(&jerr);
304 jpeg_create_decompress(&cinfo);
305 if ((fi = fopen(fname, "rb")) == NULL) {
306 fprintf(stderr, "rfxswf: file open error\n");
309 jpeg_stdio_src(&cinfo, fi);
310 jpeg_read_header(&cinfo, TRUE);
311 *width = cinfo.image_width;
312 *height = cinfo.image_height;
313 jpeg_destroy_decompress(&cinfo);
317 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
319 struct jpeg_decompress_struct cinfo;
320 struct jpeg_error_mgr jerr;
325 cinfo.err = jpeg_std_error(&jerr);
326 jpeg_create_decompress(&cinfo);
328 if ((f = fopen(fname, "rb")) == NULL) {
329 fprintf(stderr, "rfxswf: file open error\n");
333 jpeg_stdio_src(&cinfo, f);
334 jpeg_read_header(&cinfo, TRUE);
335 jpeg_start_decompress(&cinfo);
338 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
340 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
345 if (cinfo.out_color_space == JCS_GRAYSCALE) {
346 for (y = 0; y < cinfo.output_height; y++) {
348 jpeg_read_scanlines(&cinfo, &js, 1);
349 for (x = cinfo.output_width - 1; x >= 0; x--) {
350 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
352 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
354 } else if (cinfo.out_color_space == JCS_RGB) {
355 for (y = 0; y < cinfo.output_height; y++) {
356 jpeg_read_scanlines(&cinfo, &js, 1);
357 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
359 } else if (cinfo.out_color_space == JCS_YCCK) {
361 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
363 } else if (cinfo.out_color_space == JCS_YCbCr) {
364 for (y = 0; y < cinfo.output_height; y++) {
366 for (x = 0; x < cinfo.output_width; x++) {
367 int y = js[x * 3 + 0];
368 int u = js[x * 3 + 1];
369 int v = js[x * 3 + 1];
370 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
372 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
373 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
376 } else if (cinfo.out_color_space == JCS_CMYK) {
377 for (y = 0; y < cinfo.output_height; y++) {
379 jpeg_read_scanlines(&cinfo, &js, 1);
380 /* This routine seems to work for now-
381 It's a mixture of 3 different
382 CMYK->RGB conversion routines I found in the
383 web. (which all produced garbage)
384 I'm happily accepting suggestions. (mk) */
385 for (x = 0; x < cinfo.output_width; x++) {
386 int white = 255 - js[x * 4 + 3];
387 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
388 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
389 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
391 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
397 swf_SetJPEGBitsFinish(out);
398 jpeg_finish_decompress(&cinfo);
404 typedef struct _JPEGFILEMGR {
405 struct jpeg_destination_mgr mgr;
407 struct jpeg_compress_struct* cinfo;
408 struct jpeg_error_mgr* jerr;
412 static void file_init_destination(j_compress_ptr cinfo)
414 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
415 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
417 fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
420 fprintf(stderr, "Out of memory!\n");
424 dmgr->next_output_byte = fmgr->buffer;
425 dmgr->free_in_buffer = OUTBUFFER_SIZE;
428 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
430 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
431 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
434 fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
436 dmgr->next_output_byte = fmgr->buffer;
437 dmgr->free_in_buffer = OUTBUFFER_SIZE;
441 static void file_term_destination(j_compress_ptr cinfo)
443 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
444 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
447 fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
449 rfx_free(fmgr->buffer);
451 dmgr->free_in_buffer = 0;
452 dmgr->next_output_byte = 0;
455 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
458 struct jpeg_compress_struct cinfo;
459 struct jpeg_error_mgr jerr;
460 unsigned char*data2 = 0;
463 FILE*fi = fopen(filename, "wb");
466 sprintf(buf, "rfxswf: Couldn't create %s", filename);
470 data2 = rfx_calloc(width*3);
472 memset(&cinfo, 0, sizeof(cinfo));
473 memset(&jerr, 0, sizeof(jerr));
474 memset(&fmgr, 0, sizeof(fmgr));
475 cinfo.err = jpeg_std_error(&jerr);
476 jpeg_create_compress(&cinfo);
478 fmgr.mgr.init_destination = file_init_destination;
479 fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
480 fmgr.mgr.term_destination = file_term_destination;
484 cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
488 cinfo.image_width = width;
489 cinfo.image_height = height;
490 cinfo.input_components = 3;
491 cinfo.in_color_space = JCS_RGB;
492 jpeg_set_defaults(&cinfo);
493 cinfo.dct_method = JDCT_IFAST;
494 jpeg_set_quality(&cinfo,quality,TRUE);
496 //jpeg_write_tables(&cinfo);
497 //jpeg_suppress_tables(&cinfo, TRUE);
498 jpeg_start_compress(&cinfo, FALSE);
500 for(y=0;y<height;y++) {
502 RGBA*src = &pixels[y*width];
503 for(x=0;x<width;x++) {
504 data2[x*3+0] = src[x].r;
505 data2[x*3+1] = src[x].g;
506 data2[x*3+2] = src[x].b;
508 jpeg_write_scanlines(&cinfo, &data2, 1);
511 jpeg_finish_compress(&cinfo);
512 jpeg_destroy_compress(&cinfo);
517 /* jpeg_source_mgr functions */
518 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
520 TAG *tag = (TAG *) cinfo->client_data;
521 if (tag->id == ST_DEFINEBITSJPEG3) {
522 swf_SetTagPos(tag, 6);
524 swf_SetTagPos(tag, 2);
526 cinfo->src->bytes_in_buffer = 0;
528 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
530 TAG *tag = (TAG *) cinfo->client_data;
531 if (tag->data[tag->pos + 0] == 0xff &&
532 tag->data[tag->pos + 1] == 0xd9 &&
533 tag->data[tag->pos + 2] == 0xff &&
534 tag->data[tag->pos + 3] == 0xd8) {
537 if (tag->pos >= tag->len) {
538 cinfo->src->next_input_byte = 0;
539 cinfo->src->bytes_in_buffer = 0;
542 cinfo->src->next_input_byte = &tag->data[tag->pos];
543 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
547 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
549 TAG *tag = (TAG *) cinfo->client_data;
550 cinfo->src->next_input_byte = 0;
551 cinfo->src->bytes_in_buffer = 0;
554 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
556 return jpeg_resync_to_restart(cinfo, desired);
558 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
560 TAG *tag = (TAG *) cinfo->client_data;
562 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
564 struct jpeg_decompress_struct cinfo;
565 struct jpeg_error_mgr jerr;
566 struct jpeg_source_mgr mgr;
574 if (tag->id == ST_DEFINEBITSJPEG) {
575 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
578 if (tag->id == ST_DEFINEBITSJPEG3) {
580 offset = swf_GetU32(tag);
581 oldtaglen = tag->len;
584 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
589 cinfo.err = jpeg_std_error(&jerr);
590 jpeg_create_decompress(&cinfo);
592 cinfo.client_data = (void *) tag;
594 cinfo.src->init_source = tag_init_source;
595 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
596 cinfo.src->skip_input_data = tag_skip_input_data;
597 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
598 cinfo.src->term_source = tag_term_source;
599 cinfo.out_color_space = JCS_RGB;
601 jpeg_read_header(&cinfo, TRUE);
602 *width = cinfo.image_width;
603 *height = cinfo.image_height;
605 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
607 jpeg_start_decompress(&cinfo);
608 for (y = 0; y < cinfo.output_height; y++) {
609 RGBA *line = &dest[y * cinfo.image_width];
610 U8 *to = (U8 *) line;
612 jpeg_read_scanlines(&cinfo, &to, 1);
613 for (x = cinfo.output_width - 1; x >= 0; --x) {
614 int r = to[x * 3 + 0];
615 int g = to[x * 3 + 1];
616 int b = to[x * 3 + 2];
624 jpeg_finish_decompress(&cinfo);
626 jpeg_destroy_decompress(&cinfo);
630 uLongf datalen = cinfo.output_width*cinfo.output_height;
631 U8* alphadata = (U8*)rfx_alloc(datalen);
633 tag->len = oldtaglen;
634 swf_SetTagPos(tag, 6+offset);
635 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
637 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
640 for(y=0;y<cinfo.output_height;y++) {
641 RGBA*line = &dest[y*cinfo.output_width];
642 U8*aline = &alphadata[y*cinfo.output_width];
644 for(x=0;x<cinfo.output_width;x++) {
645 line[x].a = aline[x];
654 #endif // HAVE_JPEGLIB
656 // Lossless compression texture based on zlib
660 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
662 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
664 zs->avail_out = OUTBUFFER_SIZE;
666 int status = deflate(zs, Z_NO_FLUSH);
668 if (status != Z_OK) {
669 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
674 if (zs->next_out != data) {
675 swf_SetBlock(t, data, zs->next_out - data);
677 zs->avail_out = OUTBUFFER_SIZE;
680 if (zs->avail_in == 0)
690 int status = deflate(zs, Z_FINISH);
691 if (status != Z_OK && status != Z_STREAM_END) {
692 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
697 if (zs->next_out != data) {
698 swf_SetBlock(t, data, zs->next_out - data);
700 zs->avail_out = OUTBUFFER_SIZE;
703 if (status == Z_STREAM_END)
711 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
716 switch (bitmap_flags) {
718 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
720 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
726 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
730 swf_SetU8(t, bitmap_flags);
731 swf_SetU16(t, width);
732 swf_SetU16(t, height);
737 memset(&zs, 0x00, sizeof(z_stream));
741 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
742 zs.avail_in = bps * height;
745 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
750 res = -3; // zlib error
755 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
758 int bps = BYTES_PER_SCANLINE(width);
761 if (!pal) // create default palette for grayscale images
764 pal = rfx_alloc(256 * sizeof(RGBA));
765 for (i = 0; i < 256; i++) {
766 pal[i].r = pal[i].g = pal[i].b = i;
772 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
773 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
775 return -1; // parameter error
778 swf_SetU8(t, BMF_8BIT);
779 swf_SetU16(t, width);
780 swf_SetU16(t, height);
781 swf_SetU8(t, ncolors - 1); // number of pal entries
786 memset(&zs, 0x00, sizeof(z_stream));
790 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
791 U8 *zpal; // compress palette
792 if ((zpal = rfx_alloc(ncolors * 4))) {
796 /* be careful with ST_DEFINEBITSLOSSLESS2, because
797 the Flash player produces great bugs if you use too many
798 alpha colors in your palette. The only sensible result that
799 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
800 make transparent parts in sprites. That's the cause why alpha
801 handling is implemented in lossless routines of rfxswf.
803 Indeed: I haven't understood yet how flash player handles
804 alpha values different from 0 and 0xff in lossless bitmaps...
807 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
809 for (i = 0; i < ncolors; i++) {
816 zs.avail_in = 4 * ncolors;
818 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
825 zs.avail_in = 3 * ncolors;
830 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
835 zs.avail_in = (bps * height * sizeof(U8));
837 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
844 res = -2; // memory error
846 res = -3; // zlib error
855 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
857 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
860 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
862 int num = width*height;
865 data[t].r = ((int)data[t].r*data[t].a)/255;
866 data[t].g = ((int)data[t].g*data[t].a)/255;
867 data[t].b = ((int)data[t].b*data[t].a)/255;
871 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
873 int hasalpha = swf_ImageHasAlpha(data, width, height);
876 tag->id = ST_DEFINEBITSLOSSLESS;
878 tag->id = ST_DEFINEBITSLOSSLESS2;
879 swf_PreMultiplyAlpha(data, width, height);
881 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
882 if(num>1 && num<=256) {
883 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
884 int width2 = BYTES_PER_SCANLINE(width);
885 U8*data2 = (U8*)malloc(width2*height);
886 int len = width*height;
889 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
890 for(y=0;y<height;y++) {
891 RGBA*src = &data[width*y];
892 U8*dest = &data2[width2*y];
893 for(x=0;x<width;x++) {
896 if(*(U32*)&col == *(U32*)&palette[r]) {
902 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
903 col.r, col.g, col.b, col.a, num);
908 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
912 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
916 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
918 int id, format, height, width, pos;
919 uLongf datalen, datalen2;
924 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
929 if (tag->id != ST_DEFINEBITSLOSSLESS &&
930 tag->id != ST_DEFINEBITSLOSSLESS2) {
931 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
935 swf_SetTagPos(tag, 0);
936 id = swf_GetU16(tag);
937 format = swf_GetU8(tag);
944 if (format != 3 && format != 5) {
947 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
950 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
954 *dwidth = width = swf_GetU16(tag);
955 *dheight = height = swf_GetU16(tag);
957 dest = rfx_alloc(sizeof(RGBA) * width * height);
960 cols = swf_GetU8(tag) + 1;
965 datalen = (width * height * bpp / 8 + cols * 8);
970 data = rfx_alloc(datalen);
972 uncompress(data, &datalen, &tag->data[tag->pos],
973 tag->len - tag->pos);
974 } while (error == Z_BUF_ERROR);
976 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
982 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
983 for (t = 0; t < cols; t++) {
984 palette[t].r = data[pos++];
985 palette[t].g = data[pos++];
986 palette[t].b = data[pos++];
988 palette[t].a = data[pos++];
995 for (y = 0; y < height; y++) {
996 int srcwidth = width * (bpp / 8);
999 // 32 bit to 24 bit "conversion"
1000 for (x = 0; x < width; x++) {
1001 dest[pos2].r = data[pos + 1];
1002 dest[pos2].g = data[pos + 2];
1003 dest[pos2].b = data[pos + 3];
1006 pos += 4; //ignore padding byte
1009 for (x = 0; x < width; x++) {
1010 /* TODO: is un-premultiplying alpha the right thing to do?
1011 dest[pos2].r = data[pos + 1];
1012 dest[pos2].g = data[pos + 2];
1013 dest[pos2].b = data[pos + 3];*/
1014 int alpha = data[pos+0];
1016 dest[pos2].r = ((int)data[pos + 1]*255)/alpha;
1017 dest[pos2].g = ((int)data[pos + 2]*255)/alpha;
1018 dest[pos2].b = ((int)data[pos + 3]*255)/alpha;
1020 dest[pos2].r = data[pos + 1];
1021 dest[pos2].g = data[pos + 2];
1022 dest[pos2].b = data[pos + 3];
1024 dest[pos2].a = data[pos + 0]; //alpha
1030 for (x = 0; x < srcwidth; x++) {
1031 dest[pos2] = palette[data[pos++]];
1035 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1045 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1046 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1056 swf_SetU32(tag, 0); //placeholder
1057 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1058 for (y = 0; y < height; y++) {
1059 U8 scanline[3 * width];
1061 for (x = 0; x < width; x++) {
1062 scanline[p++] = bitmap[width * y + x].r;
1063 scanline[p++] = bitmap[width * y + x].g;
1064 scanline[p++] = bitmap[width * y + x].b;
1066 swf_SetJPEGBitsLine(jpeg, scanline);
1068 swf_SetJPEGBitsFinish(jpeg);
1069 PUT32(&tag->data[pos], tag->len - pos - 4);
1071 data = rfx_alloc(OUTBUFFER_SIZE);
1072 memset(&zs, 0x00, sizeof(z_stream));
1074 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1075 fprintf(stderr, "rfxswf: zlib compression failed");
1080 zs.avail_out = OUTBUFFER_SIZE;
1082 for (y = 0; y < height; y++) {
1085 for (x = 0; x < width; x++) {
1086 scanline[p++] = bitmap[width * y + x].a;
1088 zs.avail_in = width;
1089 zs.next_in = scanline;
1092 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1093 fprintf(stderr, "rfxswf: zlib compression failed");
1096 if (zs.next_out != data) {
1097 swf_SetBlock(tag, data, zs.next_out - data);
1099 zs.avail_out = OUTBUFFER_SIZE;
1108 int ret = deflate(&zs, Z_FINISH);
1109 if (ret != Z_OK && ret != Z_STREAM_END) {
1110 fprintf(stderr, "rfxswf: zlib compression failed");
1113 if (zs.next_out != data) {
1114 swf_SetBlock(tag, data, zs.next_out - data);
1116 zs.avail_out = OUTBUFFER_SIZE;
1118 if (ret == Z_STREAM_END) {
1128 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1130 TAG *tag1 = 0, *tag2 = 0;
1131 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1133 /* try lossless image */
1134 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1135 swf_SetU16(tag1, bitid);
1136 swf_SetLosslessImage(tag1, mem, width, height);
1138 /* try jpeg image */
1140 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1141 swf_SetU16(tag2, bitid);
1142 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1144 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1145 swf_SetU16(tag2, bitid);
1146 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1149 if(quality>100 || (tag1 && tag1->len < tag2->len)) {
1150 /* use the zlib version- it's smaller */
1152 if(tag) tag->next = tag1;
1154 swf_DeleteTag(tag2);
1156 /* use the jpeg version- it's smaller */
1158 if(tag) tag->next = tag2;
1160 swf_DeleteTag(tag1);
1167 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1171 swf_SetTagPos(tag, 2); // id is 2 bytes
1173 if (tag->id == ST_DEFINEBITSJPEG ||
1174 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1176 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1178 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1182 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1183 tag->id == ST_DEFINEBITSLOSSLESS2) {
1185 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1187 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1191 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1192 swf_TagGetName(tag));
1196 #undef OUTBUFFER_SIZE
1199 void swf_RemoveJPEGTables(SWF * swf)
1201 TAG *tag = swf->firstTag;
1202 TAG *tables_tag = 0;
1204 if (tag->id == ST_JPEGTABLES) {
1213 tag = swf->firstTag;
1215 if (tag->id == ST_DEFINEBITSJPEG) {
1217 void *data = rfx_alloc(len);
1218 swf_GetBlock(tag, data, tag->len);
1219 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1220 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1221 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1222 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1227 if (swf->firstTag == tables_tag)
1228 swf->firstTag = tables_tag->next;
1229 swf_DeleteTag(tables_tag);
1232 typedef struct scale_lookup {
1234 unsigned int weight;
1237 typedef struct rgba_int {
1238 unsigned int r,g,b,a;
1241 static int bicubic = 0;
1243 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1245 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1246 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1247 double fx = ((double)width)/((double)newwidth);
1250 scale_lookup_t*p_x = lookupx;
1252 if(newwidth<=width) {
1253 for(x=0;x<newwidth;x++) {
1254 double ex = px + fx;
1255 int fromx = (int)px;
1257 double rem = fromx+1-px;
1258 int i = (int)(256/fx);
1259 int xweight = (int)(rem*256/fx);
1263 if(tox>=width) tox = width-1;
1264 for(xx=fromx;xx<=tox;xx++) {
1265 if(xx==fromx && xx==tox) p_x->weight = 256;
1266 else if(xx==fromx) p_x->weight = xweight;
1267 else if(xx==tox) p_x->weight = 256-w;
1268 else p_x->weight = i;
1276 for(x=0;x<newwidth;x++) {
1278 int ix2 = ((int)px)+1;
1280 if(ix2>=width) ix2=width-1;
1284 p_x[0].weight = (int)(256*(1-r));
1286 p_x[1].weight = 256-p_x[0].weight;
1292 lblockx[newwidth] = p_x;
1296 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1299 int len = width*height;
1301 U32* img = (U32*)data;
1302 U32 color1 = img[0];
1304 for(t=1;t<len;t++) {
1305 if(img[t] != color1) {
1310 *(U32*)&colors[0] = color1;
1311 *(U32*)&colors[1] = color2;
1312 for(t=0;t<len;t++) {
1313 if(img[t] == color1) {
1316 img[t] = 0xffffffff;
1321 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1324 int len = width*height;
1326 for(t=0;t<len;t++) {
1328 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1329 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1330 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1331 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1335 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1339 scale_lookup_t *p, **lblockx,**lblocky;
1342 RGBA monochrome_colors[2];
1344 if(newwidth<1 || newheight<1)
1347 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1349 encodeMonochromeImage(data, width, height, monochrome_colors);
1352 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1353 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1355 lblockx = make_scale_lookup(width, newwidth);
1356 lblocky = make_scale_lookup(height, newheight);
1358 for(p=lblocky[0];p<lblocky[newheight];p++)
1361 for(y=0;y<newheight;y++) {
1362 RGBA*destline = &newdata[y*newwidth];
1364 /* create lookup table for y */
1365 rgba_int_t*l = tmpline;
1366 scale_lookup_t*p_y,*p_x;
1367 memset(tmpline, 0, width*sizeof(rgba_int_t));
1368 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1369 RGBA*line = &data[p_y->pos];
1371 int weight = p_y->weight;
1372 for(x=0;x<width;x++) {
1373 tmpline[x].r += line[x].r*weight;
1374 tmpline[x].g += line[x].g*weight;
1375 tmpline[x].b += line[x].b*weight;
1376 tmpline[x].a += line[x].a*weight;
1380 /* process x direction */
1382 for(x=0;x<newwidth;x++) {
1383 unsigned int r=0,g=0,b=0,a=0;
1384 scale_lookup_t*p_x_to = lblockx[x+1];
1386 rgba_int_t* col = &tmpline[p_x->pos];
1387 unsigned int weight = p_x->weight;
1393 } while (p_x<p_x_to);
1395 destline->r = r >> 16;
1396 destline->g = g >> 16;
1397 destline->b = b >> 16;
1398 destline->a = a >> 16;
1405 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);