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;
160 U32* cpal = &pal[t*256];
162 palette[i++] = *(RGBA*)(&cpal[s]);
173 typedef struct _JPEGDESTMGR {
174 struct jpeg_destination_mgr mgr;
177 struct jpeg_compress_struct cinfo;
178 struct jpeg_error_mgr jerr;
179 } JPEGDESTMGR, *LPJPEGDESTMGR;
181 // Destination manager callbacks
183 static void RFXSWF_init_destination(j_compress_ptr cinfo)
185 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
186 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
187 dmgr->mgr.next_output_byte = dmgr->buffer;
188 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
191 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
193 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
194 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
195 dmgr->mgr.next_output_byte = dmgr->buffer;
196 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
200 static void RFXSWF_term_destination(j_compress_ptr cinfo)
202 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
203 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
204 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
205 rfx_free(dmgr->buffer);
206 dmgr->mgr.free_in_buffer = 0;
209 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
213 // redirect compression lib output to local SWF Tag structure
215 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
217 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
219 jpeg_create_compress(&jpeg->cinfo);
221 jpeg->mgr.init_destination = RFXSWF_init_destination;
222 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
223 jpeg->mgr.term_destination = RFXSWF_term_destination;
227 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
231 jpeg->cinfo.image_width = width;
232 jpeg->cinfo.image_height = height;
233 jpeg->cinfo.input_components = 3;
234 jpeg->cinfo.in_color_space = JCS_RGB;
236 jpeg_set_defaults(&jpeg->cinfo);
237 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
239 // write tables to SWF
241 jpeg_write_tables(&jpeg->cinfo);
243 // compess image to SWF
245 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
246 jpeg_start_compress(&jpeg->cinfo, FALSE);
248 return (JPEGBITS *) jpeg;
251 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
253 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
256 jpeg_write_scanlines(&jpeg->cinfo, data, n);
260 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
262 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
265 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
267 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
270 jpeg_finish_compress(&jpeg->cinfo);
275 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
280 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
281 for (y = 0; y < height; y++) {
282 U8 scanline[3 * width];
284 for (x = 0; x < width; x++) {
285 scanline[p++] = bitmap[width * y + x].r;
286 scanline[p++] = bitmap[width * y + x].g;
287 scanline[p++] = bitmap[width * y + x].b;
289 swf_SetJPEGBitsLine(jpeg, scanline);
291 swf_SetJPEGBitsFinish(jpeg);
294 void swf_GetJPEGSize(char *fname, int *width, int *height)
296 struct jpeg_decompress_struct cinfo;
297 struct jpeg_error_mgr jerr;
301 cinfo.err = jpeg_std_error(&jerr);
302 jpeg_create_decompress(&cinfo);
303 if ((fi = fopen(fname, "rb")) == NULL) {
304 fprintf(stderr, "rfxswf: file open error\n");
307 jpeg_stdio_src(&cinfo, fi);
308 jpeg_read_header(&cinfo, TRUE);
309 *width = cinfo.image_width;
310 *height = cinfo.image_height;
311 jpeg_destroy_decompress(&cinfo);
315 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
317 struct jpeg_decompress_struct cinfo;
318 struct jpeg_error_mgr jerr;
323 cinfo.err = jpeg_std_error(&jerr);
324 jpeg_create_decompress(&cinfo);
326 if ((f = fopen(fname, "rb")) == NULL) {
327 fprintf(stderr, "rfxswf: file open error\n");
331 jpeg_stdio_src(&cinfo, f);
332 jpeg_read_header(&cinfo, TRUE);
333 jpeg_start_decompress(&cinfo);
336 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
338 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
343 if (cinfo.out_color_space == JCS_GRAYSCALE) {
344 for (y = 0; y < cinfo.output_height; y++) {
346 jpeg_read_scanlines(&cinfo, &js, 1);
347 for (x = cinfo.output_width - 1; x >= 0; x--) {
348 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
350 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
352 } else if (cinfo.out_color_space == JCS_RGB) {
353 for (y = 0; y < cinfo.output_height; y++) {
354 jpeg_read_scanlines(&cinfo, &js, 1);
355 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
357 } else if (cinfo.out_color_space == JCS_YCCK) {
359 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
361 } else if (cinfo.out_color_space == JCS_YCbCr) {
362 for (y = 0; y < cinfo.output_height; y++) {
364 for (x = 0; x < cinfo.output_width; x++) {
365 int y = js[x * 3 + 0];
366 int u = js[x * 3 + 1];
367 int v = js[x * 3 + 1];
368 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
370 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
371 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
374 } else if (cinfo.out_color_space == JCS_CMYK) {
375 for (y = 0; y < cinfo.output_height; y++) {
377 jpeg_read_scanlines(&cinfo, &js, 1);
378 /* This routine seems to work for now-
379 It's a mixture of 3 different
380 CMYK->RGB conversion routines I found in the
381 web. (which all produced garbage)
382 I'm happily accepting suggestions. (mk) */
383 for (x = 0; x < cinfo.output_width; x++) {
384 int white = 255 - js[x * 4 + 3];
385 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
386 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
387 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
389 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
394 swf_SetJPEGBitsFinish(out);
395 jpeg_finish_decompress(&cinfo);
401 /* jpeg_source_mgr functions */
402 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
404 TAG *tag = (TAG *) cinfo->client_data;
405 swf_SetTagPos(tag, 2);
406 cinfo->src->bytes_in_buffer = 0;
408 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
410 TAG *tag = (TAG *) cinfo->client_data;
411 if (tag->data[tag->pos + 0] == 0xff &&
412 tag->data[tag->pos + 1] == 0xd9 &&
413 tag->data[tag->pos + 2] == 0xff &&
414 tag->data[tag->pos + 3] == 0xd8) {
417 if (tag->pos >= tag->len) {
418 cinfo->src->next_input_byte = 0;
419 cinfo->src->bytes_in_buffer = 0;
422 cinfo->src->next_input_byte = &tag->data[tag->pos];
423 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
427 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
429 TAG *tag = (TAG *) cinfo->client_data;
430 cinfo->src->next_input_byte = 0;
431 cinfo->src->bytes_in_buffer = 0;
434 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
436 return jpeg_resync_to_restart(cinfo, desired);
438 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
440 TAG *tag = (TAG *) cinfo->client_data;
442 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
444 struct jpeg_decompress_struct cinfo;
445 struct jpeg_error_mgr jerr;
446 struct jpeg_source_mgr mgr;
452 if (tag->id == ST_DEFINEBITSJPEG) {
454 "rfxswf: extracting from definebitsjpeg not yet supported");
457 if (tag->id == ST_DEFINEBITSJPEG3) {
459 "rfxswf: extracting from definebitsjpeg3 not yet supported");
463 cinfo.err = jpeg_std_error(&jerr);
464 jpeg_create_decompress(&cinfo);
466 cinfo.client_data = (void *) tag;
468 cinfo.src->init_source = tag_init_source;
469 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
470 cinfo.src->skip_input_data = tag_skip_input_data;
471 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
472 cinfo.src->term_source = tag_term_source;
473 cinfo.out_color_space = JCS_RGB;
475 jpeg_read_header(&cinfo, TRUE);
476 *width = cinfo.image_width;
477 *height = cinfo.image_height;
479 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
481 jpeg_start_decompress(&cinfo);
482 for (y = 0; y < cinfo.output_height; y++) {
483 RGBA *line = &dest[y * cinfo.image_width];
484 U8 *to = (U8 *) line;
486 jpeg_read_scanlines(&cinfo, &to, 1);
487 for (x = cinfo.output_width - 1; x >= 0; --x) {
488 int r = to[x * 3 + 0];
489 int g = to[x * 3 + 1];
490 int b = to[x * 3 + 2];
498 jpeg_finish_decompress(&cinfo);
500 jpeg_destroy_decompress(&cinfo);
504 #endif // HAVE_JPEGLIB
506 // Lossless compression texture based on zlib
510 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
512 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
514 zs->avail_out = OUTBUFFER_SIZE;
516 int status = deflate(zs, Z_NO_FLUSH);
518 if (status != Z_OK) {
519 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
524 if (zs->next_out != data) {
525 swf_SetBlock(t, data, zs->next_out - data);
527 zs->avail_out = OUTBUFFER_SIZE;
530 if (zs->avail_in == 0)
540 int status = deflate(zs, Z_FINISH);
541 if (status != Z_OK && status != Z_STREAM_END) {
542 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
547 if (zs->next_out != data) {
548 swf_SetBlock(t, data, zs->next_out - data);
550 zs->avail_out = OUTBUFFER_SIZE;
553 if (status == Z_STREAM_END)
561 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
566 switch (bitmap_flags) {
568 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
570 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
576 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
580 swf_SetU8(t, bitmap_flags);
581 swf_SetU16(t, width);
582 swf_SetU16(t, height);
587 memset(&zs, 0x00, sizeof(z_stream));
591 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
592 zs.avail_in = bps * height;
595 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
600 res = -3; // zlib error
605 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
608 int bps = BYTES_PER_SCANLINE(width);
611 if (!pal) // create default palette for grayscale images
614 pal = rfx_alloc(256 * sizeof(RGBA));
615 for (i = 0; i < 256; i++) {
616 pal[i].r = pal[i].g = pal[i].b = i;
622 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
623 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
625 return -1; // parameter error
628 swf_SetU8(t, BMF_8BIT);
629 swf_SetU16(t, width);
630 swf_SetU16(t, height);
631 swf_SetU8(t, ncolors - 1); // number of pal entries
636 memset(&zs, 0x00, sizeof(z_stream));
640 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
641 U8 *zpal; // compress palette
642 if ((zpal = rfx_alloc(ncolors * 4))) {
646 /* be careful with ST_DEFINEBITSLOSSLESS2, because
647 the Flash player produces great bugs if you use too many
648 alpha colors in your palette. The only sensible result that
649 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
650 make transparent parts in sprites. That's the cause why alpha
651 handling is implemented in lossless routines of rfxswf.
653 Indeed: I haven't understood yet how flash player handles
654 alpha values different from 0 and 0xff in lossless bitmaps...
657 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
659 for (i = 0; i < ncolors; i++) {
666 zs.avail_in = 4 * ncolors;
668 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
675 zs.avail_in = 3 * ncolors;
680 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
685 zs.avail_in = (bps * height * sizeof(U8));
687 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
694 res = -2; // memory error
696 res = -3; // zlib error
705 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
707 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
710 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
712 int num = width*height;
715 data[t].r = ((int)data[t].r*data[t].a)/255;
716 data[t].g = ((int)data[t].g*data[t].a)/255;
717 data[t].b = ((int)data[t].b*data[t].a)/255;
721 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
723 int hasalpha = swf_ImageHasAlpha(data, width, height);
726 tag->id = ST_DEFINEBITSLOSSLESS;
728 tag->id = ST_DEFINEBITSLOSSLESS2;
729 swf_PreMultiplyAlpha(data, width, height);
731 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
732 if(num>1 && num<=256) {
733 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
734 int width2 = BYTES_PER_SCANLINE(width);
735 U8*data2 = (U8*)malloc(width2*height);
736 int len = width*height;
739 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
740 for(y=0;y<height;y++) {
741 RGBA*src = &data[width*y];
742 U8*dest = &data2[width2*y];
743 for(x=0;x<width;x++) {
746 if(*(U32*)&col == *(U32*)&palette[r]) {
752 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
753 col.r, col.g, col.b, col.a, num);
758 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
762 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
766 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
768 int id, format, height, width, pos;
769 U32 datalen, datalen2;
774 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
779 if (tag->id != ST_DEFINEBITSLOSSLESS &&
780 tag->id != ST_DEFINEBITSLOSSLESS2) {
781 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
785 swf_SetTagPos(tag, 0);
786 id = swf_GetU16(tag);
787 format = swf_GetU8(tag);
794 if (format != 3 && format != 5) {
797 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
800 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
804 *dwidth = width = swf_GetU16(tag);
805 *dheight = height = swf_GetU16(tag);
807 dest = rfx_alloc(sizeof(RGBA) * width * height);
810 cols = swf_GetU8(tag) + 1;
815 datalen = (width * height * bpp / 8 + cols * 8);
820 data = rfx_alloc(datalen);
822 uncompress(data, &datalen, &tag->data[tag->pos],
823 tag->len - tag->pos);
824 } while (error == Z_BUF_ERROR);
826 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
832 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
833 for (t = 0; t < cols; t++) {
834 palette[t].r = data[pos++];
835 palette[t].g = data[pos++];
836 palette[t].b = data[pos++];
838 palette[t].a = data[pos++];
845 for (y = 0; y < height; y++) {
846 int srcwidth = width * (bpp / 8);
849 // 32 bit to 24 bit "conversion"
850 for (x = 0; x < width; x++) {
851 dest[pos2].r = data[pos + 1];
852 dest[pos2].g = data[pos + 2];
853 dest[pos2].b = data[pos + 3];
856 pos += 4; //ignore padding byte
859 for (x = 0; x < width; x++) {
860 /* TODO: is un-premultiplying alpha the right thing to do?
861 dest[pos2].r = data[pos + 1];
862 dest[pos2].g = data[pos + 2];
863 dest[pos2].b = data[pos + 3];*/
864 dest[pos2].r = ((int)data[pos + 1]*255)/(int)data[pos+0];
865 dest[pos2].g = ((int)data[pos + 2]*255)/(int)data[pos+0];
866 dest[pos2].b = ((int)data[pos + 3]*255)/(int)data[pos+0];
867 dest[pos2].a = data[pos + 0]; //alpha
873 for (x = 0; x < srcwidth; x++) {
874 dest[pos2] = palette[data[pos++]];
878 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
888 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
889 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
899 swf_SetU32(tag, 0); //placeholder
900 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
901 for (y = 0; y < height; y++) {
902 U8 scanline[3 * width];
904 for (x = 0; x < width; x++) {
905 scanline[p++] = bitmap[width * y + x].r;
906 scanline[p++] = bitmap[width * y + x].g;
907 scanline[p++] = bitmap[width * y + x].b;
909 swf_SetJPEGBitsLine(jpeg, scanline);
911 swf_SetJPEGBitsFinish(jpeg);
912 PUT32(&tag->data[pos], tag->len - pos - 4);
914 data = rfx_alloc(OUTBUFFER_SIZE);
915 memset(&zs, 0x00, sizeof(z_stream));
917 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
918 fprintf(stderr, "rfxswf: zlib compression failed");
923 zs.avail_out = OUTBUFFER_SIZE;
925 for (y = 0; y < height; y++) {
928 for (x = 0; x < width; x++) {
929 scanline[p++] = bitmap[width * y + x].a;
932 zs.next_in = scanline;
935 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
936 fprintf(stderr, "rfxswf: zlib compression failed");
939 if (zs.next_out != data) {
940 swf_SetBlock(tag, data, zs.next_out - data);
942 zs.avail_out = OUTBUFFER_SIZE;
951 int ret = deflate(&zs, Z_FINISH);
952 if (ret != Z_OK && ret != Z_STREAM_END) {
953 fprintf(stderr, "rfxswf: zlib compression failed");
956 if (zs.next_out != data) {
957 swf_SetBlock(tag, data, zs.next_out - data);
959 zs.avail_out = OUTBUFFER_SIZE;
961 if (ret == Z_STREAM_END) {
971 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
973 TAG *tag1 = 0, *tag2 = 0;
974 int has_alpha = swf_ImageHasAlpha(mem,width,height);
976 /* try lossless image */
977 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
978 swf_SetU16(tag1, bitid);
979 swf_SetLosslessImage(tag1, mem, width, height);
983 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
984 swf_SetU16(tag2, bitid);
985 swf_SetJPEGBits3(tag2, width, height, mem, quality);
987 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
988 swf_SetU16(tag2, bitid);
989 swf_SetJPEGBits2(tag2, width, height, mem, quality);
992 if(tag1 && tag1->len < tag2->len) {
993 /* use the zlib version- it's smaller */
995 if(tag) tag->next = tag1;
999 /* use the jpeg version- it's smaller */
1001 if(tag) tag->next = tag2;
1003 swf_DeleteTag(tag1);
1010 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1013 if (tag->id == ST_DEFINEBITSJPEG ||
1014 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1016 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1018 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1022 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1023 tag->id == ST_DEFINEBITSLOSSLESS2) {
1025 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1027 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1031 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1032 swf_TagGetName(tag));
1036 #undef OUTBUFFER_SIZE
1039 void swf_RemoveJPEGTables(SWF * swf)
1041 TAG *tag = swf->firstTag;
1042 TAG *tables_tag = 0;
1044 if (tag->id == ST_JPEGTABLES) {
1053 tag = swf->firstTag;
1055 if (tag->id == ST_DEFINEBITSJPEG) {
1057 void *data = rfx_alloc(len);
1058 swf_GetBlock(tag, data, tag->len);
1059 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1060 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1061 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1062 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1067 if (swf->firstTag == tables_tag)
1068 swf->firstTag = tables_tag->next;
1069 swf_DeleteTag(tables_tag);
1072 typedef struct scale_lookup {
1074 unsigned int weight;
1077 typedef struct rgba_int {
1078 unsigned int r,g,b,a;
1081 static int bicubic = 0;
1083 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1085 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1086 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1087 double fx = ((double)width)/((double)newwidth);
1090 scale_lookup_t*p_x = lookupx;
1092 if(newwidth<=width) {
1093 for(x=0;x<newwidth;x++) {
1094 double ex = px + fx;
1095 int fromx = (int)px;
1097 double rem = fromx+1-px;
1098 int i = (int)(256/fx);
1099 int xweight = (int)(rem*256/fx);
1103 if(tox>=width) tox = width-1;
1104 for(xx=fromx;xx<=tox;xx++) {
1105 if(xx==fromx && xx==tox) p_x->weight = 256;
1106 else if(xx==fromx) p_x->weight = xweight;
1107 else if(xx==tox) p_x->weight = 256-w;
1108 else p_x->weight = i;
1116 for(x=0;x<newwidth;x++) {
1118 int ix2 = ((int)px)+1;
1120 if(ix2>=width) ix2=width-1;
1124 p_x[0].weight = (int)(256*(1-r));
1126 p_x[1].weight = 256-p_x[0].weight;
1132 lblockx[newwidth] = p_x;
1135 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1139 scale_lookup_t *p, **lblockx,**lblocky;
1142 if(newwidth<1 || newheight<1)
1145 /* this is bad because this scaler doesn't yet handle monochrome
1146 images with 2 colors in a way that the final image hasn't more
1148 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2)
1149 fprintf(stderr, "Warning: scaling monochrome image\n");
1151 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1152 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1154 lblockx = make_scale_lookup(width, newwidth);
1155 lblocky = make_scale_lookup(height, newheight);
1157 for(p=lblocky[0];p<lblocky[newheight];p++)
1160 for(y=0;y<newheight;y++) {
1161 RGBA*destline = &newdata[y*newwidth];
1163 /* create lookup table for y */
1164 rgba_int_t*l = tmpline;
1165 scale_lookup_t*p_y,*p_x;
1166 memset(tmpline, 0, width*sizeof(rgba_int_t));
1167 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1168 RGBA*line = &data[p_y->pos];
1170 int weight = p_y->weight;
1171 for(x=0;x<width;x++) {
1172 tmpline[x].r += line[x].r*weight;
1173 tmpline[x].g += line[x].g*weight;
1174 tmpline[x].b += line[x].b*weight;
1175 tmpline[x].a += line[x].a*weight;
1179 /* process x direction */
1181 for(x=0;x<newwidth;x++) {
1182 unsigned int r=0,g=0,b=0,a=0;
1183 scale_lookup_t*p_x_to = lblockx[x+1];
1185 rgba_int_t* col = &tmpline[p_x->pos];
1186 unsigned int weight = p_x->weight;
1192 } while (p_x<p_x_to);
1194 destline->r = r >> 16;
1195 destline->g = g >> 16;
1196 destline->b = b >> 16;
1197 destline->a = a >> 16;