3 Bitmap functions (needs libjpeg)
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
27 #include "../../config.h"
44 #endif // HAVE_JPEGLIB
46 #include "../rfxswf.h"
48 #define OUTBUFFER_SIZE 0x8000
50 int swf_ImageHasAlpha(RGBA*img, int width, int height)
52 int len = width*height;
56 if(img[t].a >= 4 && img[t].a < 0xfc)
64 int swf_ImageGetNumberOfPaletteEntries2(RGBA*_img, int width, int height)
66 int len = width*height;
68 U32* img = (U32*)_img;
72 if(img[t] != color1) {
81 if(img[t] != color1 && img[t] != color2) {
88 /*int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
90 int len = width*height;
95 int palette_overflow = 0;
98 if(sizeof(RGBA)!=sizeof(U32))
99 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
101 lastcol32 = pal32[palsize++] = *(U32*)&img[0];
105 U32 col32 = *(U32*)&img[t];
109 for(i=0;i<palsize;i++) {
110 if(col32 == pal32[i])
115 palette_overflow = 1;
118 pal32[palsize++] = col32;
125 memcpy(palette, pal, palsize*sizeof(RGBA));
129 int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
131 int len = width*height;
136 int palette_overflow = 0;
139 pal = (U32*)malloc(65536*sizeof(U32));
141 memset(size, 0, sizeof(size));
143 if(sizeof(RGBA)!=sizeof(U32))
144 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
146 lastcol32 = (*(U32*)&img[0])^0xffffffff; // don't match
150 U32 col32 = *(U32*)&img[t];
155 if(col32 == lastcol32)
157 hash = (col32 >> 17) ^ col32;
158 hash ^= ((hash>>8) + 1) ^ hash;
162 cpal = &pal[hash*256];
163 for(i=0;i<csize;i++) {
169 palette_overflow = 1;
172 cpal[size[hash]++] = col32;
177 if(palette_overflow) {
186 U32* cpal = &pal[t*256];
188 palette[i++] = *(RGBA*)(&cpal[s]);
199 typedef struct _JPEGDESTMGR {
200 struct jpeg_destination_mgr mgr;
203 struct jpeg_compress_struct cinfo;
204 struct jpeg_error_mgr jerr;
205 } JPEGDESTMGR, *LPJPEGDESTMGR;
207 // Destination manager callbacks
209 static void RFXSWF_init_destination(j_compress_ptr cinfo)
211 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
212 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
213 dmgr->mgr.next_output_byte = dmgr->buffer;
214 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
217 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
219 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
220 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
221 dmgr->mgr.next_output_byte = dmgr->buffer;
222 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
226 static void RFXSWF_term_destination(j_compress_ptr cinfo)
228 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
229 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
230 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
231 rfx_free(dmgr->buffer);
232 dmgr->mgr.free_in_buffer = 0;
235 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
239 // redirect compression lib output to local SWF Tag structure
241 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
243 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
245 jpeg_create_compress(&jpeg->cinfo);
247 jpeg->mgr.init_destination = RFXSWF_init_destination;
248 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
249 jpeg->mgr.term_destination = RFXSWF_term_destination;
253 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
257 jpeg->cinfo.image_width = width;
258 jpeg->cinfo.image_height = height;
259 jpeg->cinfo.input_components = 3;
260 jpeg->cinfo.in_color_space = JCS_RGB;
262 jpeg_set_defaults(&jpeg->cinfo);
263 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
265 // write tables to SWF
267 jpeg_write_tables(&jpeg->cinfo);
269 // compess image to SWF
271 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
272 jpeg_start_compress(&jpeg->cinfo, FALSE);
274 return (JPEGBITS *) jpeg;
277 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
279 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
282 jpeg_write_scanlines(&jpeg->cinfo, data, n);
286 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
288 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
291 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
293 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
296 jpeg_finish_compress(&jpeg->cinfo);
297 jpeg_destroy_compress(&jpeg->cinfo);
302 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
307 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
308 U8 *scanline = (U8*)rfx_alloc(3 * width);
309 for (y = 0; y < height; y++) {
311 for (x = 0; x < width; x++) {
312 scanline[p++] = bitmap[width * y + x].r;
313 scanline[p++] = bitmap[width * y + x].g;
314 scanline[p++] = bitmap[width * y + x].b;
316 swf_SetJPEGBitsLine(jpeg, scanline);
319 swf_SetJPEGBitsFinish(jpeg);
322 void swf_GetJPEGSize(char *fname, int *width, int *height)
324 struct jpeg_decompress_struct cinfo;
325 struct jpeg_error_mgr jerr;
329 cinfo.err = jpeg_std_error(&jerr);
330 jpeg_create_decompress(&cinfo);
331 if ((fi = fopen(fname, "rb")) == NULL) {
332 fprintf(stderr, "rfxswf: file open error\n");
335 jpeg_stdio_src(&cinfo, fi);
336 jpeg_read_header(&cinfo, TRUE);
337 *width = cinfo.image_width;
338 *height = cinfo.image_height;
339 jpeg_destroy_decompress(&cinfo);
343 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
345 struct jpeg_decompress_struct cinfo;
346 struct jpeg_error_mgr jerr;
351 cinfo.err = jpeg_std_error(&jerr);
352 jpeg_create_decompress(&cinfo);
354 if ((f = fopen(fname, "rb")) == NULL) {
355 fprintf(stderr, "rfxswf: file open error\n");
359 jpeg_stdio_src(&cinfo, f);
360 jpeg_read_header(&cinfo, TRUE);
361 jpeg_start_decompress(&cinfo);
364 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
366 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
371 if (cinfo.out_color_space == JCS_GRAYSCALE) {
372 for (y = 0; y < cinfo.output_height; y++) {
374 jpeg_read_scanlines(&cinfo, &js, 1);
375 for (x = cinfo.output_width - 1; x >= 0; x--) {
376 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
378 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
380 } else if (cinfo.out_color_space == JCS_RGB) {
381 for (y = 0; y < cinfo.output_height; y++) {
382 jpeg_read_scanlines(&cinfo, &js, 1);
383 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
385 } else if (cinfo.out_color_space == JCS_YCCK) {
387 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
389 } else if (cinfo.out_color_space == JCS_YCbCr) {
390 for (y = 0; y < cinfo.output_height; y++) {
392 for (x = 0; x < cinfo.output_width; x++) {
393 int y = js[x * 3 + 0];
394 int u = js[x * 3 + 1];
395 int v = js[x * 3 + 1];
396 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
398 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
399 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
402 } else if (cinfo.out_color_space == JCS_CMYK) {
403 for (y = 0; y < cinfo.output_height; y++) {
405 jpeg_read_scanlines(&cinfo, &js, 1);
406 /* This routine seems to work for now-
407 It's a mixture of 3 different
408 CMYK->RGB conversion routines I found in the
409 web. (which all produced garbage)
410 I'm happily accepting suggestions. (mk) */
411 for (x = 0; x < cinfo.output_width; x++) {
412 int white = 255 - js[x * 4 + 3];
413 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
414 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
415 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
417 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
423 swf_SetJPEGBitsFinish(out);
424 jpeg_finish_decompress(&cinfo);
430 typedef struct _JPEGFILEMGR {
431 struct jpeg_destination_mgr mgr;
433 struct jpeg_compress_struct* cinfo;
434 struct jpeg_error_mgr* jerr;
438 static void file_init_destination(j_compress_ptr cinfo)
440 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
441 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
443 fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
446 fprintf(stderr, "Out of memory!\n");
450 dmgr->next_output_byte = fmgr->buffer;
451 dmgr->free_in_buffer = OUTBUFFER_SIZE;
454 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
456 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
457 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
460 fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
462 dmgr->next_output_byte = fmgr->buffer;
463 dmgr->free_in_buffer = OUTBUFFER_SIZE;
467 static void file_term_destination(j_compress_ptr cinfo)
469 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
470 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
473 fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
475 rfx_free(fmgr->buffer);
477 dmgr->free_in_buffer = 0;
478 dmgr->next_output_byte = 0;
481 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
484 struct jpeg_compress_struct cinfo;
485 struct jpeg_error_mgr jerr;
486 unsigned char*data2 = 0;
489 FILE*fi = fopen(filename, "wb");
492 sprintf(buf, "rfxswf: Couldn't create %s", filename);
496 data2 = (unsigned char *)rfx_calloc(width*3);
498 memset(&cinfo, 0, sizeof(cinfo));
499 memset(&jerr, 0, sizeof(jerr));
500 memset(&fmgr, 0, sizeof(fmgr));
501 cinfo.err = jpeg_std_error(&jerr);
502 jpeg_create_compress(&cinfo);
504 fmgr.mgr.init_destination = file_init_destination;
505 fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
506 fmgr.mgr.term_destination = file_term_destination;
510 cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
514 cinfo.image_width = width;
515 cinfo.image_height = height;
516 cinfo.input_components = 3;
517 cinfo.in_color_space = JCS_RGB;
518 jpeg_set_defaults(&cinfo);
519 cinfo.dct_method = JDCT_IFAST;
520 jpeg_set_quality(&cinfo,quality,TRUE);
522 //jpeg_write_tables(&cinfo);
523 //jpeg_suppress_tables(&cinfo, TRUE);
524 jpeg_start_compress(&cinfo, FALSE);
526 for(y=0;y<height;y++) {
528 RGBA*src = &pixels[y*width];
529 for(x=0;x<width;x++) {
530 data2[x*3+0] = src[x].r;
531 data2[x*3+1] = src[x].g;
532 data2[x*3+2] = src[x].b;
534 jpeg_write_scanlines(&cinfo, &data2, 1);
537 jpeg_finish_compress(&cinfo);
538 jpeg_destroy_compress(&cinfo);
543 /* jpeg_source_mgr functions */
544 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
546 TAG *tag = (TAG *) cinfo->client_data;
547 if (tag->id == ST_DEFINEBITSJPEG3) {
548 swf_SetTagPos(tag, 6);
550 swf_SetTagPos(tag, 2);
552 cinfo->src->bytes_in_buffer = 0;
554 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
556 TAG *tag = (TAG *) cinfo->client_data;
557 if (tag->data[tag->pos + 0] == 0xff &&
558 tag->data[tag->pos + 1] == 0xd9 &&
559 tag->data[tag->pos + 2] == 0xff &&
560 tag->data[tag->pos + 3] == 0xd8) {
563 if (tag->pos >= tag->len) {
564 cinfo->src->next_input_byte = 0;
565 cinfo->src->bytes_in_buffer = 0;
568 cinfo->src->next_input_byte = &tag->data[tag->pos];
569 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
573 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
575 TAG *tag = (TAG *) cinfo->client_data;
576 cinfo->src->next_input_byte = 0;
577 cinfo->src->bytes_in_buffer = 0;
580 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
582 return jpeg_resync_to_restart(cinfo, desired);
584 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
586 TAG *tag = (TAG *) cinfo->client_data;
588 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
590 struct jpeg_decompress_struct cinfo;
591 struct jpeg_error_mgr jerr;
592 struct jpeg_source_mgr mgr;
600 if (tag->id == ST_DEFINEBITSJPEG) {
601 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
604 if (tag->id == ST_DEFINEBITSJPEG3) {
606 offset = swf_GetU32(tag);
607 oldtaglen = tag->len;
610 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
615 cinfo.err = jpeg_std_error(&jerr);
616 jpeg_create_decompress(&cinfo);
618 cinfo.client_data = (void *) tag;
620 cinfo.src->init_source = tag_init_source;
621 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
622 cinfo.src->skip_input_data = tag_skip_input_data;
623 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
624 cinfo.src->term_source = tag_term_source;
625 cinfo.out_color_space = JCS_RGB;
627 jpeg_read_header(&cinfo, TRUE);
628 *width = cinfo.image_width;
629 *height = cinfo.image_height;
631 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
633 jpeg_start_decompress(&cinfo);
634 for (y = 0; y < cinfo.output_height; y++) {
635 RGBA *line = &dest[y * cinfo.image_width];
636 U8 *to = (U8 *) line;
638 jpeg_read_scanlines(&cinfo, &to, 1);
639 for (x = cinfo.output_width - 1; x >= 0; --x) {
640 int r = to[x * 3 + 0];
641 int g = to[x * 3 + 1];
642 int b = to[x * 3 + 2];
650 jpeg_finish_decompress(&cinfo);
652 jpeg_destroy_decompress(&cinfo);
656 uLongf datalen = cinfo.output_width*cinfo.output_height;
657 U8* alphadata = (U8*)rfx_alloc(datalen);
659 tag->len = oldtaglen;
660 swf_SetTagPos(tag, 6+offset);
661 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
663 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
666 for(y=0;y<cinfo.output_height;y++) {
667 RGBA*line = &dest[y*cinfo.output_width];
668 U8*aline = &alphadata[y*cinfo.output_width];
670 for(x=0;x<cinfo.output_width;x++) {
671 line[x].a = aline[x];
680 #endif // HAVE_JPEGLIB
682 // Lossless compression texture based on zlib
686 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
688 U8 *data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
690 zs->avail_out = OUTBUFFER_SIZE;
692 int status = deflate(zs, Z_NO_FLUSH);
694 if (status != Z_OK) {
695 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
700 if (zs->next_out != data) {
701 swf_SetBlock(t, data, zs->next_out - data);
703 zs->avail_out = OUTBUFFER_SIZE;
706 if (zs->avail_in == 0)
716 int status = deflate(zs, Z_FINISH);
717 if (status != Z_OK && status != Z_STREAM_END) {
718 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
723 if (zs->next_out != data) {
724 swf_SetBlock(t, data, zs->next_out - data);
726 zs->avail_out = OUTBUFFER_SIZE;
729 if (status == Z_STREAM_END)
737 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
742 switch (bitmap_flags) {
744 return swf_SetLosslessBitsIndexed(t, width, height, (U8*)bitmap, NULL, 256);
746 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
752 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
756 swf_SetU8(t, bitmap_flags);
757 swf_SetU16(t, width);
758 swf_SetU16(t, height);
763 memset(&zs, 0x00, sizeof(z_stream));
767 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
768 zs.avail_in = bps * height;
769 zs.next_in = (Bytef *)bitmap;
771 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
776 res = -3; // zlib error
781 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
784 int bps = BYTES_PER_SCANLINE(width);
787 if (!pal) // create default palette for grayscale images
790 pal = (RGBA*)rfx_alloc(256 * sizeof(RGBA));
791 for (i = 0; i < 256; i++) {
792 pal[i].r = pal[i].g = pal[i].b = i;
798 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
799 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
801 return -1; // parameter error
804 swf_SetU8(t, BMF_8BIT);
805 swf_SetU16(t, width);
806 swf_SetU16(t, height);
807 swf_SetU8(t, ncolors - 1); // number of pal entries
812 memset(&zs, 0x00, sizeof(z_stream));
816 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
817 U8 *zpal; // compress palette
818 if ((zpal = (U8*)rfx_alloc(ncolors * 4))) {
822 /* be careful with ST_DEFINEBITSLOSSLESS2, because
823 the Flash player produces great bugs if you use too many
824 alpha colors in your palette. The only sensible result that
825 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
826 make transparent parts in sprites. That's the cause why alpha
827 handling is implemented in lossless routines of rfxswf.
829 Indeed: I haven't understood yet how flash player handles
830 alpha values different from 0 and 0xff in lossless bitmaps...
833 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
835 for (i = 0; i < ncolors; i++) {
842 zs.avail_in = 4 * ncolors;
844 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
851 zs.avail_in = 3 * ncolors;
856 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
861 zs.avail_in = (bps * height * sizeof(U8));
863 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
870 res = -2; // memory error
872 res = -3; // zlib error
881 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
883 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
886 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
888 int num = width*height;
891 data[t].r = ((int)data[t].r*data[t].a)/255;
892 data[t].g = ((int)data[t].g*data[t].a)/255;
893 data[t].b = ((int)data[t].b*data[t].a)/255;
897 /* expects mem to be non-premultiplied */
898 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
900 int hasalpha = swf_ImageHasAlpha(data, width, height);
903 tag->id = ST_DEFINEBITSLOSSLESS;
905 tag->id = ST_DEFINEBITSLOSSLESS2;
906 swf_PreMultiplyAlpha(data, width, height);
908 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
909 if(num>1 && num<=256) {
910 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
911 int width2 = BYTES_PER_SCANLINE(width);
912 U8*data2 = (U8*)malloc(width2*height);
913 int len = width*height;
916 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
917 for(y=0;y<height;y++) {
918 RGBA*src = &data[width*y];
919 U8*dest = &data2[width2*y];
920 for(x=0;x<width;x++) {
923 if(*(U32*)&col == *(U32*)&palette[r]) {
929 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
930 col.r, col.g, col.b, col.a, num);
935 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
939 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
943 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
945 int id, format, height, width, pos;
946 uLongf datalen, datalen2;
951 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
956 if (tag->id != ST_DEFINEBITSLOSSLESS &&
957 tag->id != ST_DEFINEBITSLOSSLESS2) {
958 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
962 swf_SetTagPos(tag, 0);
963 id = swf_GetU16(tag);
964 format = swf_GetU8(tag);
971 if (format != 3 && format != 5) {
974 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
977 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
981 *dwidth = width = swf_GetU16(tag);
982 *dheight = height = swf_GetU16(tag);
984 dest = (RGBA*)rfx_alloc(sizeof(RGBA) * width * height);
987 cols = swf_GetU8(tag) + 1;
992 datalen = (width * height * bpp / 8 + cols * 8);
997 data = (U8*)rfx_alloc(datalen);
999 uncompress(data, &datalen, &tag->data[tag->pos],
1000 tag->len - tag->pos);
1001 } while (error == Z_BUF_ERROR);
1002 if (error != Z_OK) {
1003 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
1009 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
1010 for (t = 0; t < cols; t++) {
1011 palette[t].r = data[pos++];
1012 palette[t].g = data[pos++];
1013 palette[t].b = data[pos++];
1015 palette[t].a = data[pos++];
1022 for (y = 0; y < height; y++) {
1023 int srcwidth = width * (bpp / 8);
1026 // 32 bit to 24 bit "conversion"
1027 for (x = 0; x < width; x++) {
1028 dest[pos2].r = data[pos + 1];
1029 dest[pos2].g = data[pos + 2];
1030 dest[pos2].b = data[pos + 3];
1033 pos += 4; //ignore padding byte
1036 for (x = 0; x < width; x++) {
1037 /* remove premultiplication */
1038 int alpha = data[pos+0];
1040 alpha = 0xff0000/alpha;
1041 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1042 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1043 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1044 dest[pos2].a = data[pos + 0]; //alpha
1050 for (x = 0; x < srcwidth; x++) {
1051 dest[pos2] = palette[data[pos++]];
1055 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1065 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1067 /* expects bitmap to be non-premultiplied */
1068 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1078 swf_SetU32(tag, 0); //placeholder
1079 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1080 U8 *scanline = (U8*)rfx_alloc(3 * width);
1081 for (y = 0; y < height; y++) {
1083 for (x = 0; x < width; x++) {
1084 //int ia = bitmap[width*y+x].a;
1086 // /* remove premultiplication */
1087 // ia = 0xff0000/ia;
1089 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1090 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1091 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1092 scanline[p++] = bitmap[width * y + x].r;
1093 scanline[p++] = bitmap[width * y + x].g;
1094 scanline[p++] = bitmap[width * y + x].b;
1096 swf_SetJPEGBitsLine(jpeg, scanline);
1099 swf_SetJPEGBitsFinish(jpeg);
1100 PUT32(&tag->data[pos], tag->len - pos - 4);
1102 data = (U8*)rfx_alloc(OUTBUFFER_SIZE);
1103 memset(&zs, 0x00, sizeof(z_stream));
1105 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1106 fprintf(stderr, "rfxswf: zlib compression failed");
1111 zs.avail_out = OUTBUFFER_SIZE;
1113 scanline = (U8*)rfx_alloc(width);
1114 for (y = 0; y < height; y++) {
1116 for (x = 0; x < width; x++) {
1117 scanline[p++] = bitmap[width * y + x].a;
1119 zs.avail_in = width;
1120 zs.next_in = scanline;
1123 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1124 fprintf(stderr, "rfxswf: zlib compression failed");
1127 if (zs.next_out != data) {
1128 swf_SetBlock(tag, data, zs.next_out - data);
1130 zs.avail_out = OUTBUFFER_SIZE;
1141 int ret = deflate(&zs, Z_FINISH);
1142 if (ret != Z_OK && ret != Z_STREAM_END) {
1143 fprintf(stderr, "rfxswf: zlib compression failed");
1146 if (zs.next_out != data) {
1147 swf_SetBlock(tag, data, zs.next_out - data);
1149 zs.avail_out = OUTBUFFER_SIZE;
1151 if (ret == Z_STREAM_END) {
1161 /* expects mem to be non-premultiplied */
1162 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1164 TAG *tag1 = 0, *tag2 = 0;
1165 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1167 /* try lossless image */
1168 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1169 swf_SetU16(tag1, bitid);
1170 swf_SetLosslessImage(tag1, mem, width, height);
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);
1183 if(quality>100 || (tag1 && tag1->len < tag2->len)) {
1184 /* use the zlib version- it's smaller */
1186 if(tag) tag->next = tag1;
1188 swf_DeleteTag(tag2);
1190 /* use the jpeg version- it's smaller */
1192 if(tag) tag->next = tag2;
1194 swf_DeleteTag(tag1);
1201 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1205 swf_SetTagPos(tag, 2); // id is 2 bytes
1207 if (tag->id == ST_DEFINEBITSJPEG ||
1208 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1210 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1212 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1216 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1217 tag->id == ST_DEFINEBITSLOSSLESS2) {
1219 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1221 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1225 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1226 swf_TagGetName(tag));
1230 #undef OUTBUFFER_SIZE
1233 void swf_RemoveJPEGTables(SWF * swf)
1235 TAG *tag = swf->firstTag;
1236 TAG *tables_tag = 0;
1238 if (tag->id == ST_JPEGTABLES) {
1247 tag = swf->firstTag;
1249 if (tag->id == ST_DEFINEBITSJPEG) {
1251 void *data = rfx_alloc(len);
1252 swf_GetBlock(tag, (U8*)data, tag->len);
1253 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1254 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1255 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1256 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1261 if (swf->firstTag == tables_tag)
1262 swf->firstTag = tables_tag->next;
1263 swf_DeleteTag(tables_tag);
1266 typedef struct scale_lookup {
1268 unsigned int weight;
1271 typedef struct rgba_int {
1272 unsigned int r,g,b,a;
1275 static int bicubic = 0;
1277 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1279 scale_lookup_t*lookupx = (scale_lookup_t*)malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1280 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1281 double fx = ((double)width)/((double)newwidth);
1284 scale_lookup_t*p_x = lookupx;
1286 if(newwidth<=width) {
1287 for(x=0;x<newwidth;x++) {
1288 double ex = px + fx;
1289 int fromx = (int)px;
1291 double rem = fromx+1-px;
1292 int i = (int)(256/fx);
1293 int xweight = (int)(rem*256/fx);
1297 if(tox>=width) tox = width-1;
1298 for(xx=fromx;xx<=tox;xx++) {
1299 if(xx==fromx && xx==tox) p_x->weight = 256;
1300 else if(xx==fromx) p_x->weight = xweight;
1301 else if(xx==tox) p_x->weight = 256-w;
1302 else p_x->weight = i;
1310 for(x=0;x<newwidth;x++) {
1312 int ix2 = ((int)px)+1;
1314 if(ix2>=width) ix2=width-1;
1318 p_x[0].weight = (int)(256*(1-r));
1320 p_x[1].weight = 256-p_x[0].weight;
1326 lblockx[newwidth] = p_x;
1330 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1333 int len = width*height;
1335 U32* img = (U32*)data;
1336 U32 color1 = img[0];
1338 for(t=1;t<len;t++) {
1339 if(img[t] != color1) {
1344 *(U32*)&colors[0] = color1;
1345 *(U32*)&colors[1] = color2;
1346 for(t=0;t<len;t++) {
1347 if(img[t] == color1) {
1350 img[t] = 0xffffffff;
1355 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1358 int len = width*height;
1360 for(t=0;t<len;t++) {
1362 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1363 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1364 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1365 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1369 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1373 scale_lookup_t *p, **lblockx,**lblocky;
1376 RGBA monochrome_colors[2];
1378 if(newwidth<1 || newheight<1)
1381 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1383 encodeMonochromeImage(data, width, height, monochrome_colors);
1386 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1387 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1389 lblockx = make_scale_lookup(width, newwidth);
1390 lblocky = make_scale_lookup(height, newheight);
1392 for(p=lblocky[0];p<lblocky[newheight];p++)
1395 for(y=0;y<newheight;y++) {
1396 RGBA*destline = &newdata[y*newwidth];
1398 /* create lookup table for y */
1399 rgba_int_t*l = tmpline;
1400 scale_lookup_t*p_y,*p_x;
1401 memset(tmpline, 0, width*sizeof(rgba_int_t));
1402 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1403 RGBA*line = &data[p_y->pos];
1405 int weight = p_y->weight;
1406 for(x=0;x<width;x++) {
1407 tmpline[x].r += line[x].r*weight;
1408 tmpline[x].g += line[x].g*weight;
1409 tmpline[x].b += line[x].b*weight;
1410 tmpline[x].a += line[x].a*weight;
1414 /* process x direction */
1416 for(x=0;x<newwidth;x++) {
1417 unsigned int r=0,g=0,b=0,a=0;
1418 scale_lookup_t*p_x_to = lblockx[x+1];
1420 rgba_int_t* col = &tmpline[p_x->pos];
1421 unsigned int weight = p_x->weight;
1427 } while (p_x<p_x_to);
1429 destline->r = r >> 16;
1430 destline->g = g >> 16;
1431 destline->b = b >> 16;
1432 destline->a = a >> 16;
1439 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);