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);
273 jpeg_destroy_compress(&jpeg->cinfo);
278 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
283 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
284 for (y = 0; y < height; y++) {
285 U8 scanline[3 * width];
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);
294 swf_SetJPEGBitsFinish(jpeg);
297 void swf_GetJPEGSize(char *fname, int *width, int *height)
299 struct jpeg_decompress_struct cinfo;
300 struct jpeg_error_mgr jerr;
304 cinfo.err = jpeg_std_error(&jerr);
305 jpeg_create_decompress(&cinfo);
306 if ((fi = fopen(fname, "rb")) == NULL) {
307 fprintf(stderr, "rfxswf: file open error\n");
310 jpeg_stdio_src(&cinfo, fi);
311 jpeg_read_header(&cinfo, TRUE);
312 *width = cinfo.image_width;
313 *height = cinfo.image_height;
314 jpeg_destroy_decompress(&cinfo);
318 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
320 struct jpeg_decompress_struct cinfo;
321 struct jpeg_error_mgr jerr;
326 cinfo.err = jpeg_std_error(&jerr);
327 jpeg_create_decompress(&cinfo);
329 if ((f = fopen(fname, "rb")) == NULL) {
330 fprintf(stderr, "rfxswf: file open error\n");
334 jpeg_stdio_src(&cinfo, f);
335 jpeg_read_header(&cinfo, TRUE);
336 jpeg_start_decompress(&cinfo);
339 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
341 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
346 if (cinfo.out_color_space == JCS_GRAYSCALE) {
347 for (y = 0; y < cinfo.output_height; y++) {
349 jpeg_read_scanlines(&cinfo, &js, 1);
350 for (x = cinfo.output_width - 1; x >= 0; x--) {
351 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
353 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
355 } else if (cinfo.out_color_space == JCS_RGB) {
356 for (y = 0; y < cinfo.output_height; y++) {
357 jpeg_read_scanlines(&cinfo, &js, 1);
358 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
360 } else if (cinfo.out_color_space == JCS_YCCK) {
362 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
364 } else if (cinfo.out_color_space == JCS_YCbCr) {
365 for (y = 0; y < cinfo.output_height; y++) {
367 for (x = 0; x < cinfo.output_width; x++) {
368 int y = js[x * 3 + 0];
369 int u = js[x * 3 + 1];
370 int v = js[x * 3 + 1];
371 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
373 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
374 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
377 } else if (cinfo.out_color_space == JCS_CMYK) {
378 for (y = 0; y < cinfo.output_height; y++) {
380 jpeg_read_scanlines(&cinfo, &js, 1);
381 /* This routine seems to work for now-
382 It's a mixture of 3 different
383 CMYK->RGB conversion routines I found in the
384 web. (which all produced garbage)
385 I'm happily accepting suggestions. (mk) */
386 for (x = 0; x < cinfo.output_width; x++) {
387 int white = 255 - js[x * 4 + 3];
388 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
389 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
390 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
392 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
398 swf_SetJPEGBitsFinish(out);
399 jpeg_finish_decompress(&cinfo);
405 typedef struct _JPEGFILEMGR {
406 struct jpeg_destination_mgr mgr;
408 struct jpeg_compress_struct* cinfo;
409 struct jpeg_error_mgr* jerr;
413 static void file_init_destination(j_compress_ptr cinfo)
415 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
416 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
418 fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
421 fprintf(stderr, "Out of memory!\n");
425 dmgr->next_output_byte = fmgr->buffer;
426 dmgr->free_in_buffer = OUTBUFFER_SIZE;
429 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
431 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
432 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
435 fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
437 dmgr->next_output_byte = fmgr->buffer;
438 dmgr->free_in_buffer = OUTBUFFER_SIZE;
442 static void file_term_destination(j_compress_ptr cinfo)
444 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
445 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
448 fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
450 rfx_free(fmgr->buffer);
452 dmgr->free_in_buffer = 0;
453 dmgr->next_output_byte = 0;
456 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
459 struct jpeg_compress_struct cinfo;
460 struct jpeg_error_mgr jerr;
461 unsigned char*data2 = 0;
464 FILE*fi = fopen(filename, "wb");
467 sprintf(buf, "rfxswf: Couldn't create %s", filename);
471 data2 = rfx_calloc(width*3);
473 memset(&cinfo, 0, sizeof(cinfo));
474 memset(&jerr, 0, sizeof(jerr));
475 memset(&fmgr, 0, sizeof(fmgr));
476 cinfo.err = jpeg_std_error(&jerr);
477 jpeg_create_compress(&cinfo);
479 fmgr.mgr.init_destination = file_init_destination;
480 fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
481 fmgr.mgr.term_destination = file_term_destination;
485 cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
489 cinfo.image_width = width;
490 cinfo.image_height = height;
491 cinfo.input_components = 3;
492 cinfo.in_color_space = JCS_RGB;
493 jpeg_set_defaults(&cinfo);
494 cinfo.dct_method = JDCT_IFAST;
495 jpeg_set_quality(&cinfo,quality,TRUE);
497 //jpeg_write_tables(&cinfo);
498 //jpeg_suppress_tables(&cinfo, TRUE);
499 jpeg_start_compress(&cinfo, FALSE);
501 for(y=0;y<height;y++) {
503 RGBA*src = &pixels[y*width];
504 for(x=0;x<width;x++) {
505 data2[x*3+0] = src[x].r;
506 data2[x*3+1] = src[x].g;
507 data2[x*3+2] = src[x].b;
509 jpeg_write_scanlines(&cinfo, &data2, 1);
512 jpeg_finish_compress(&cinfo);
513 jpeg_destroy_compress(&cinfo);
518 /* jpeg_source_mgr functions */
519 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
521 TAG *tag = (TAG *) cinfo->client_data;
522 if (tag->id == ST_DEFINEBITSJPEG3) {
523 swf_SetTagPos(tag, 6);
525 swf_SetTagPos(tag, 2);
527 cinfo->src->bytes_in_buffer = 0;
529 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
531 TAG *tag = (TAG *) cinfo->client_data;
532 if (tag->data[tag->pos + 0] == 0xff &&
533 tag->data[tag->pos + 1] == 0xd9 &&
534 tag->data[tag->pos + 2] == 0xff &&
535 tag->data[tag->pos + 3] == 0xd8) {
538 if (tag->pos >= tag->len) {
539 cinfo->src->next_input_byte = 0;
540 cinfo->src->bytes_in_buffer = 0;
543 cinfo->src->next_input_byte = &tag->data[tag->pos];
544 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
548 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
550 TAG *tag = (TAG *) cinfo->client_data;
551 cinfo->src->next_input_byte = 0;
552 cinfo->src->bytes_in_buffer = 0;
555 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
557 return jpeg_resync_to_restart(cinfo, desired);
559 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
561 TAG *tag = (TAG *) cinfo->client_data;
563 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
565 struct jpeg_decompress_struct cinfo;
566 struct jpeg_error_mgr jerr;
567 struct jpeg_source_mgr mgr;
575 if (tag->id == ST_DEFINEBITSJPEG) {
576 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
579 if (tag->id == ST_DEFINEBITSJPEG3) {
581 offset = swf_GetU32(tag);
582 oldtaglen = tag->len;
585 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
590 cinfo.err = jpeg_std_error(&jerr);
591 jpeg_create_decompress(&cinfo);
593 cinfo.client_data = (void *) tag;
595 cinfo.src->init_source = tag_init_source;
596 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
597 cinfo.src->skip_input_data = tag_skip_input_data;
598 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
599 cinfo.src->term_source = tag_term_source;
600 cinfo.out_color_space = JCS_RGB;
602 jpeg_read_header(&cinfo, TRUE);
603 *width = cinfo.image_width;
604 *height = cinfo.image_height;
606 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
608 jpeg_start_decompress(&cinfo);
609 for (y = 0; y < cinfo.output_height; y++) {
610 RGBA *line = &dest[y * cinfo.image_width];
611 U8 *to = (U8 *) line;
613 jpeg_read_scanlines(&cinfo, &to, 1);
614 for (x = cinfo.output_width - 1; x >= 0; --x) {
615 int r = to[x * 3 + 0];
616 int g = to[x * 3 + 1];
617 int b = to[x * 3 + 2];
625 jpeg_finish_decompress(&cinfo);
627 jpeg_destroy_decompress(&cinfo);
631 uLongf datalen = cinfo.output_width*cinfo.output_height;
632 U8* alphadata = (U8*)rfx_alloc(datalen);
634 tag->len = oldtaglen;
635 swf_SetTagPos(tag, 6+offset);
636 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
638 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
641 for(y=0;y<cinfo.output_height;y++) {
642 RGBA*line = &dest[y*cinfo.output_width];
643 U8*aline = &alphadata[y*cinfo.output_width];
645 for(x=0;x<cinfo.output_width;x++) {
646 line[x].a = aline[x];
655 #endif // HAVE_JPEGLIB
657 // Lossless compression texture based on zlib
661 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
663 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
665 zs->avail_out = OUTBUFFER_SIZE;
667 int status = deflate(zs, Z_NO_FLUSH);
669 if (status != Z_OK) {
670 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
675 if (zs->next_out != data) {
676 swf_SetBlock(t, data, zs->next_out - data);
678 zs->avail_out = OUTBUFFER_SIZE;
681 if (zs->avail_in == 0)
691 int status = deflate(zs, Z_FINISH);
692 if (status != Z_OK && status != Z_STREAM_END) {
693 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
698 if (zs->next_out != data) {
699 swf_SetBlock(t, data, zs->next_out - data);
701 zs->avail_out = OUTBUFFER_SIZE;
704 if (status == Z_STREAM_END)
712 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
717 switch (bitmap_flags) {
719 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
721 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
727 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
731 swf_SetU8(t, bitmap_flags);
732 swf_SetU16(t, width);
733 swf_SetU16(t, height);
738 memset(&zs, 0x00, sizeof(z_stream));
742 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
743 zs.avail_in = bps * height;
746 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
751 res = -3; // zlib error
756 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
759 int bps = BYTES_PER_SCANLINE(width);
762 if (!pal) // create default palette for grayscale images
765 pal = rfx_alloc(256 * sizeof(RGBA));
766 for (i = 0; i < 256; i++) {
767 pal[i].r = pal[i].g = pal[i].b = i;
773 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
774 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
776 return -1; // parameter error
779 swf_SetU8(t, BMF_8BIT);
780 swf_SetU16(t, width);
781 swf_SetU16(t, height);
782 swf_SetU8(t, ncolors - 1); // number of pal entries
787 memset(&zs, 0x00, sizeof(z_stream));
791 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
792 U8 *zpal; // compress palette
793 if ((zpal = rfx_alloc(ncolors * 4))) {
797 /* be careful with ST_DEFINEBITSLOSSLESS2, because
798 the Flash player produces great bugs if you use too many
799 alpha colors in your palette. The only sensible result that
800 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
801 make transparent parts in sprites. That's the cause why alpha
802 handling is implemented in lossless routines of rfxswf.
804 Indeed: I haven't understood yet how flash player handles
805 alpha values different from 0 and 0xff in lossless bitmaps...
808 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
810 for (i = 0; i < ncolors; i++) {
817 zs.avail_in = 4 * ncolors;
819 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
826 zs.avail_in = 3 * ncolors;
831 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
836 zs.avail_in = (bps * height * sizeof(U8));
838 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
845 res = -2; // memory error
847 res = -3; // zlib error
856 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
858 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
861 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
863 int num = width*height;
866 data[t].r = ((int)data[t].r*data[t].a)/255;
867 data[t].g = ((int)data[t].g*data[t].a)/255;
868 data[t].b = ((int)data[t].b*data[t].a)/255;
872 /* expects mem to be non-premultiplied */
873 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
875 int hasalpha = swf_ImageHasAlpha(data, width, height);
878 tag->id = ST_DEFINEBITSLOSSLESS;
880 tag->id = ST_DEFINEBITSLOSSLESS2;
881 swf_PreMultiplyAlpha(data, width, height);
883 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
884 if(num>1 && num<=256) {
885 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
886 int width2 = BYTES_PER_SCANLINE(width);
887 U8*data2 = (U8*)malloc(width2*height);
888 int len = width*height;
891 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
892 for(y=0;y<height;y++) {
893 RGBA*src = &data[width*y];
894 U8*dest = &data2[width2*y];
895 for(x=0;x<width;x++) {
898 if(*(U32*)&col == *(U32*)&palette[r]) {
904 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
905 col.r, col.g, col.b, col.a, num);
910 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
914 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
918 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
920 int id, format, height, width, pos;
921 uLongf datalen, datalen2;
926 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
931 if (tag->id != ST_DEFINEBITSLOSSLESS &&
932 tag->id != ST_DEFINEBITSLOSSLESS2) {
933 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
937 swf_SetTagPos(tag, 0);
938 id = swf_GetU16(tag);
939 format = swf_GetU8(tag);
946 if (format != 3 && format != 5) {
949 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
952 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
956 *dwidth = width = swf_GetU16(tag);
957 *dheight = height = swf_GetU16(tag);
959 dest = rfx_alloc(sizeof(RGBA) * width * height);
962 cols = swf_GetU8(tag) + 1;
967 datalen = (width * height * bpp / 8 + cols * 8);
972 data = rfx_alloc(datalen);
974 uncompress(data, &datalen, &tag->data[tag->pos],
975 tag->len - tag->pos);
976 } while (error == Z_BUF_ERROR);
978 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
984 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
985 for (t = 0; t < cols; t++) {
986 palette[t].r = data[pos++];
987 palette[t].g = data[pos++];
988 palette[t].b = data[pos++];
990 palette[t].a = data[pos++];
997 for (y = 0; y < height; y++) {
998 int srcwidth = width * (bpp / 8);
1001 // 32 bit to 24 bit "conversion"
1002 for (x = 0; x < width; x++) {
1003 dest[pos2].r = data[pos + 1];
1004 dest[pos2].g = data[pos + 2];
1005 dest[pos2].b = data[pos + 3];
1008 pos += 4; //ignore padding byte
1011 for (x = 0; x < width; x++) {
1012 /* remove premultiplication */
1013 int alpha = data[pos+0];
1015 alpha = 0xff0000/alpha;
1016 dest[pos2].r = (data[pos + 1]*alpha)>>16;
1017 dest[pos2].g = (data[pos + 2]*alpha)>>16;
1018 dest[pos2].b = (data[pos + 3]*alpha)>>16;
1019 dest[pos2].a = data[pos + 0]; //alpha
1025 for (x = 0; x < srcwidth; x++) {
1026 dest[pos2] = palette[data[pos++]];
1030 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1040 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1042 /* expects bitmap to be non-premultiplied */
1043 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1053 swf_SetU32(tag, 0); //placeholder
1054 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1055 for (y = 0; y < height; y++) {
1056 U8 scanline[3 * width];
1058 for (x = 0; x < width; x++) {
1059 //int ia = bitmap[width*y+x].a;
1061 // /* remove premultiplication */
1062 // ia = 0xff0000/ia;
1064 //scanline[p++] = (bitmap[width * y + x].r*ia)>>16;
1065 //scanline[p++] = (bitmap[width * y + x].g*ia)>>16;
1066 //scanline[p++] = (bitmap[width * y + x].b*ia)>>16;
1067 scanline[p++] = bitmap[width * y + x].r;
1068 scanline[p++] = bitmap[width * y + x].g;
1069 scanline[p++] = bitmap[width * y + x].b;
1071 swf_SetJPEGBitsLine(jpeg, scanline);
1073 swf_SetJPEGBitsFinish(jpeg);
1074 PUT32(&tag->data[pos], tag->len - pos - 4);
1076 data = rfx_alloc(OUTBUFFER_SIZE);
1077 memset(&zs, 0x00, sizeof(z_stream));
1079 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1080 fprintf(stderr, "rfxswf: zlib compression failed");
1085 zs.avail_out = OUTBUFFER_SIZE;
1087 for (y = 0; y < height; y++) {
1090 for (x = 0; x < width; x++) {
1091 scanline[p++] = bitmap[width * y + x].a;
1093 zs.avail_in = width;
1094 zs.next_in = scanline;
1097 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1098 fprintf(stderr, "rfxswf: zlib compression failed");
1101 if (zs.next_out != data) {
1102 swf_SetBlock(tag, data, zs.next_out - data);
1104 zs.avail_out = OUTBUFFER_SIZE;
1113 int ret = deflate(&zs, Z_FINISH);
1114 if (ret != Z_OK && ret != Z_STREAM_END) {
1115 fprintf(stderr, "rfxswf: zlib compression failed");
1118 if (zs.next_out != data) {
1119 swf_SetBlock(tag, data, zs.next_out - data);
1121 zs.avail_out = OUTBUFFER_SIZE;
1123 if (ret == Z_STREAM_END) {
1133 /* expects mem to be non-premultiplied */
1134 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1136 TAG *tag1 = 0, *tag2 = 0;
1137 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1139 /* try lossless image */
1140 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1141 swf_SetU16(tag1, bitid);
1142 swf_SetLosslessImage(tag1, mem, width, height);
1144 /* try jpeg image */
1146 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1147 swf_SetU16(tag2, bitid);
1148 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1150 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1151 swf_SetU16(tag2, bitid);
1152 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1155 if(quality>100 || (tag1 && tag1->len < tag2->len)) {
1156 /* use the zlib version- it's smaller */
1158 if(tag) tag->next = tag1;
1160 swf_DeleteTag(tag2);
1162 /* use the jpeg version- it's smaller */
1164 if(tag) tag->next = tag2;
1166 swf_DeleteTag(tag1);
1173 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1177 swf_SetTagPos(tag, 2); // id is 2 bytes
1179 if (tag->id == ST_DEFINEBITSJPEG ||
1180 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1182 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1184 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1188 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1189 tag->id == ST_DEFINEBITSLOSSLESS2) {
1191 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1193 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1197 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1198 swf_TagGetName(tag));
1202 #undef OUTBUFFER_SIZE
1205 void swf_RemoveJPEGTables(SWF * swf)
1207 TAG *tag = swf->firstTag;
1208 TAG *tables_tag = 0;
1210 if (tag->id == ST_JPEGTABLES) {
1219 tag = swf->firstTag;
1221 if (tag->id == ST_DEFINEBITSJPEG) {
1223 void *data = rfx_alloc(len);
1224 swf_GetBlock(tag, data, tag->len);
1225 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1226 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1227 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1228 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1233 if (swf->firstTag == tables_tag)
1234 swf->firstTag = tables_tag->next;
1235 swf_DeleteTag(tables_tag);
1238 typedef struct scale_lookup {
1240 unsigned int weight;
1243 typedef struct rgba_int {
1244 unsigned int r,g,b,a;
1247 static int bicubic = 0;
1249 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1251 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1252 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1253 double fx = ((double)width)/((double)newwidth);
1256 scale_lookup_t*p_x = lookupx;
1258 if(newwidth<=width) {
1259 for(x=0;x<newwidth;x++) {
1260 double ex = px + fx;
1261 int fromx = (int)px;
1263 double rem = fromx+1-px;
1264 int i = (int)(256/fx);
1265 int xweight = (int)(rem*256/fx);
1269 if(tox>=width) tox = width-1;
1270 for(xx=fromx;xx<=tox;xx++) {
1271 if(xx==fromx && xx==tox) p_x->weight = 256;
1272 else if(xx==fromx) p_x->weight = xweight;
1273 else if(xx==tox) p_x->weight = 256-w;
1274 else p_x->weight = i;
1282 for(x=0;x<newwidth;x++) {
1284 int ix2 = ((int)px)+1;
1286 if(ix2>=width) ix2=width-1;
1290 p_x[0].weight = (int)(256*(1-r));
1292 p_x[1].weight = 256-p_x[0].weight;
1298 lblockx[newwidth] = p_x;
1302 static void encodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1305 int len = width*height;
1307 U32* img = (U32*)data;
1308 U32 color1 = img[0];
1310 for(t=1;t<len;t++) {
1311 if(img[t] != color1) {
1316 *(U32*)&colors[0] = color1;
1317 *(U32*)&colors[1] = color2;
1318 for(t=0;t<len;t++) {
1319 if(img[t] == color1) {
1322 img[t] = 0xffffffff;
1327 static void decodeMonochromeImage(RGBA*data, int width, int height, RGBA*colors)
1330 int len = width*height;
1332 for(t=0;t<len;t++) {
1334 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
1335 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
1336 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
1337 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
1341 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1345 scale_lookup_t *p, **lblockx,**lblocky;
1348 RGBA monochrome_colors[2];
1350 if(newwidth<1 || newheight<1)
1353 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1355 encodeMonochromeImage(data, width, height, monochrome_colors);
1358 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1359 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1361 lblockx = make_scale_lookup(width, newwidth);
1362 lblocky = make_scale_lookup(height, newheight);
1364 for(p=lblocky[0];p<lblocky[newheight];p++)
1367 for(y=0;y<newheight;y++) {
1368 RGBA*destline = &newdata[y*newwidth];
1370 /* create lookup table for y */
1371 rgba_int_t*l = tmpline;
1372 scale_lookup_t*p_y,*p_x;
1373 memset(tmpline, 0, width*sizeof(rgba_int_t));
1374 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1375 RGBA*line = &data[p_y->pos];
1377 int weight = p_y->weight;
1378 for(x=0;x<width;x++) {
1379 tmpline[x].r += line[x].r*weight;
1380 tmpline[x].g += line[x].g*weight;
1381 tmpline[x].b += line[x].b*weight;
1382 tmpline[x].a += line[x].a*weight;
1386 /* process x direction */
1388 for(x=0;x<newwidth;x++) {
1389 unsigned int r=0,g=0,b=0,a=0;
1390 scale_lookup_t*p_x_to = lblockx[x+1];
1392 rgba_int_t* col = &tmpline[p_x->pos];
1393 unsigned int weight = p_x->weight;
1399 } while (p_x<p_x_to);
1401 destline->r = r >> 16;
1402 destline->g = g >> 16;
1403 destline->b = b >> 16;
1404 destline->a = a >> 16;
1411 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);