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 /* expects mem to be non-premultiplied */
872 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
874 int hasalpha = swf_ImageHasAlpha(data, width, height);
877 tag->id = ST_DEFINEBITSLOSSLESS;
879 tag->id = ST_DEFINEBITSLOSSLESS2;
880 swf_PreMultiplyAlpha(data, width, height);
882 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
883 if(num>1 && num<=256) {
884 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
885 int width2 = BYTES_PER_SCANLINE(width);
886 U8*data2 = (U8*)malloc(width2*height);
887 int len = width*height;
890 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
891 for(y=0;y<height;y++) {
892 RGBA*src = &data[width*y];
893 U8*dest = &data2[width2*y];
894 for(x=0;x<width;x++) {
897 if(*(U32*)&col == *(U32*)&palette[r]) {
903 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
904 col.r, col.g, col.b, col.a, num);
909 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
913 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
917 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
919 int id, format, height, width, pos;
920 uLongf datalen, datalen2;
925 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
930 if (tag->id != ST_DEFINEBITSLOSSLESS &&
931 tag->id != ST_DEFINEBITSLOSSLESS2) {
932 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
936 swf_SetTagPos(tag, 0);
937 id = swf_GetU16(tag);
938 format = swf_GetU8(tag);
945 if (format != 3 && format != 5) {
948 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
951 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
955 *dwidth = width = swf_GetU16(tag);
956 *dheight = height = swf_GetU16(tag);
958 dest = rfx_alloc(sizeof(RGBA) * width * height);
961 cols = swf_GetU8(tag) + 1;
966 datalen = (width * height * bpp / 8 + cols * 8);
971 data = rfx_alloc(datalen);
973 uncompress(data, &datalen, &tag->data[tag->pos],
974 tag->len - tag->pos);
975 } while (error == Z_BUF_ERROR);
977 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
983 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
984 for (t = 0; t < cols; t++) {
985 palette[t].r = data[pos++];
986 palette[t].g = data[pos++];
987 palette[t].b = data[pos++];
989 palette[t].a = data[pos++];
996 for (y = 0; y < height; y++) {
997 int srcwidth = width * (bpp / 8);
1000 // 32 bit to 24 bit "conversion"
1001 for (x = 0; x < width; x++) {
1002 dest[pos2].r = data[pos + 1];
1003 dest[pos2].g = data[pos + 2];
1004 dest[pos2].b = data[pos + 3];
1007 pos += 4; //ignore padding byte
1010 for (x = 0; x < width; x++) {
1011 /* remove premultiplication */
1012 int alpha = data[pos+0];
1014 alpha = 0xff0000/alpha;
1015 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1016 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1017 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1018 dest[pos2].a = data[pos + 0]; //alpha
1024 for (x = 0; x < srcwidth; x++) {
1025 dest[pos2] = palette[data[pos++]];
1029 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1039 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1041 /* expects bitmap to be non-premultiplied */
1042 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1052 swf_SetU32(tag, 0); //placeholder
1053 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1054 for (y = 0; y < height; y++) {
1055 U8 scanline[3 * width];
1057 for (x = 0; x < width; x++) {
1058 //int ia = bitmap[width*y+x].a;
1060 // /* remove premultiplication */
1061 // ia = 0xff0000/ia;
1063 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1064 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1065 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1066 scanline[p++] = bitmap[width * y + x].r;
1067 scanline[p++] = bitmap[width * y + x].g;
1068 scanline[p++] = bitmap[width * y + x].b;
1070 swf_SetJPEGBitsLine(jpeg, scanline);
1072 swf_SetJPEGBitsFinish(jpeg);
1073 PUT32(&tag->data[pos], tag->len - pos - 4);
1075 data = rfx_alloc(OUTBUFFER_SIZE);
1076 memset(&zs, 0x00, sizeof(z_stream));
1078 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1079 fprintf(stderr, "rfxswf: zlib compression failed");
1084 zs.avail_out = OUTBUFFER_SIZE;
1086 for (y = 0; y < height; y++) {
1089 for (x = 0; x < width; x++) {
1090 scanline[p++] = bitmap[width * y + x].a;
1092 zs.avail_in = width;
1093 zs.next_in = scanline;
1096 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1097 fprintf(stderr, "rfxswf: zlib compression failed");
1100 if (zs.next_out != data) {
1101 swf_SetBlock(tag, data, zs.next_out - data);
1103 zs.avail_out = OUTBUFFER_SIZE;
1112 int ret = deflate(&zs, Z_FINISH);
1113 if (ret != Z_OK && ret != Z_STREAM_END) {
1114 fprintf(stderr, "rfxswf: zlib compression failed");
1117 if (zs.next_out != data) {
1118 swf_SetBlock(tag, data, zs.next_out - data);
1120 zs.avail_out = OUTBUFFER_SIZE;
1122 if (ret == Z_STREAM_END) {
1132 /* expects mem to be non-premultiplied */
1133 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1135 TAG *tag1 = 0, *tag2 = 0;
1136 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1138 /* try lossless image */
1139 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1140 swf_SetU16(tag1, bitid);
1141 swf_SetLosslessImage(tag1, mem, width, height);
1143 /* try jpeg image */
1145 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1146 swf_SetU16(tag2, bitid);
1147 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1149 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1150 swf_SetU16(tag2, bitid);
1151 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1154 if(quality>100 || (tag1 && tag1->len < tag2->len)) {
1155 /* use the zlib version- it's smaller */
1157 if(tag) tag->next = tag1;
1159 swf_DeleteTag(tag2);
1161 /* use the jpeg version- it's smaller */
1163 if(tag) tag->next = tag2;
1165 swf_DeleteTag(tag1);
1172 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1176 swf_SetTagPos(tag, 2); // id is 2 bytes
1178 if (tag->id == ST_DEFINEBITSJPEG ||
1179 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1181 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1183 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1187 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1188 tag->id == ST_DEFINEBITSLOSSLESS2) {
1190 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1192 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1196 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1197 swf_TagGetName(tag));
1201 #undef OUTBUFFER_SIZE
1204 void swf_RemoveJPEGTables(SWF * swf)
1206 TAG *tag = swf->firstTag;
1207 TAG *tables_tag = 0;
1209 if (tag->id == ST_JPEGTABLES) {
1218 tag = swf->firstTag;
1220 if (tag->id == ST_DEFINEBITSJPEG) {
1222 void *data = rfx_alloc(len);
1223 swf_GetBlock(tag, data, tag->len);
1224 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1225 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1226 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1227 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1232 if (swf->firstTag == tables_tag)
1233 swf->firstTag = tables_tag->next;
1234 swf_DeleteTag(tables_tag);
1237 typedef struct scale_lookup {
1239 unsigned int weight;
1242 typedef struct rgba_int {
1243 unsigned int r,g,b,a;
1246 static int bicubic = 0;
1248 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1250 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1251 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1252 double fx = ((double)width)/((double)newwidth);
1255 scale_lookup_t*p_x = lookupx;
1257 if(newwidth<=width) {
1258 for(x=0;x<newwidth;x++) {
1259 double ex = px + fx;
1260 int fromx = (int)px;
1262 double rem = fromx+1-px;
1263 int i = (int)(256/fx);
1264 int xweight = (int)(rem*256/fx);
1268 if(tox>=width) tox = width-1;
1269 for(xx=fromx;xx<=tox;xx++) {
1270 if(xx==fromx && xx==tox) p_x->weight = 256;
1271 else if(xx==fromx) p_x->weight = xweight;
1272 else if(xx==tox) p_x->weight = 256-w;
1273 else p_x->weight = i;
1281 for(x=0;x<newwidth;x++) {
1283 int ix2 = ((int)px)+1;
1285 if(ix2>=width) ix2=width-1;
1289 p_x[0].weight = (int)(256*(1-r));
1291 p_x[1].weight = 256-p_x[0].weight;
1297 lblockx[newwidth] = p_x;
1301 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1304 int len = width*height;
1306 U32* img = (U32*)data;
1307 U32 color1 = img[0];
1309 for(t=1;t<len;t++) {
1310 if(img[t] != color1) {
1315 *(U32*)&colors[0] = color1;
1316 *(U32*)&colors[1] = color2;
1317 for(t=0;t<len;t++) {
1318 if(img[t] == color1) {
1321 img[t] = 0xffffffff;
1326 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1329 int len = width*height;
1331 for(t=0;t<len;t++) {
1333 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1334 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1335 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1336 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1340 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1344 scale_lookup_t *p, **lblockx,**lblocky;
1347 RGBA monochrome_colors[2];
1349 if(newwidth<1 || newheight<1)
1352 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1354 encodeMonochromeImage(data, width, height, monochrome_colors);
1357 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1358 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1360 lblockx = make_scale_lookup(width, newwidth);
1361 lblocky = make_scale_lookup(height, newheight);
1363 for(p=lblocky[0];p<lblocky[newheight];p++)
1366 for(y=0;y<newheight;y++) {
1367 RGBA*destline = &newdata[y*newwidth];
1369 /* create lookup table for y */
1370 rgba_int_t*l = tmpline;
1371 scale_lookup_t*p_y,*p_x;
1372 memset(tmpline, 0, width*sizeof(rgba_int_t));
1373 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1374 RGBA*line = &data[p_y->pos];
1376 int weight = p_y->weight;
1377 for(x=0;x<width;x++) {
1378 tmpline[x].r += line[x].r*weight;
1379 tmpline[x].g += line[x].g*weight;
1380 tmpline[x].b += line[x].b*weight;
1381 tmpline[x].a += line[x].a*weight;
1385 /* process x direction */
1387 for(x=0;x<newwidth;x++) {
1388 unsigned int r=0,g=0,b=0,a=0;
1389 scale_lookup_t*p_x_to = lblockx[x+1];
1391 rgba_int_t* col = &tmpline[p_x->pos];
1392 unsigned int weight = p_x->weight;
1398 } while (p_x<p_x_to);
1400 destline->r = r >> 16;
1401 destline->g = g >> 16;
1402 destline->b = b >> 16;
1403 destline->a = a >> 16;
1410 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);