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_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
712 int hasalpha = swf_ImageHasAlpha(data, width, height);
715 tag->id = ST_DEFINEBITSLOSSLESS;
717 tag->id = ST_DEFINEBITSLOSSLESS2;
718 /* TODO: premultiply alpha? */
720 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
721 if(num>1 && num<=256) {
722 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
723 int width2 = BYTES_PER_SCANLINE(width);
724 U8*data2 = (U8*)malloc(width2*height);
725 int len = width*height;
728 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
729 for(y=0;y<height;y++) {
730 RGBA*src = &data[width*y];
731 U8*dest = &data2[width2*y];
732 for(x=0;x<width;x++) {
735 if(*(U32*)&col == *(U32*)&palette[r]) {
741 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
742 col.r, col.g, col.b, col.a, num);
747 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
751 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
755 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
757 int id, format, height, width, pos;
758 U32 datalen, datalen2;
763 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
768 if (tag->id != ST_DEFINEBITSLOSSLESS &&
769 tag->id != ST_DEFINEBITSLOSSLESS2) {
770 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
774 swf_SetTagPos(tag, 0);
775 id = swf_GetU16(tag);
776 format = swf_GetU8(tag);
783 if (format != 3 && format != 5) {
786 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
789 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
793 *dwidth = width = swf_GetU16(tag);
794 *dheight = height = swf_GetU16(tag);
796 dest = rfx_alloc(sizeof(RGBA) * width * height);
799 cols = swf_GetU8(tag) + 1;
804 datalen = (width * height * bpp / 8 + cols * 8);
809 data = rfx_alloc(datalen);
811 uncompress(data, &datalen, &tag->data[tag->pos],
812 tag->len - tag->pos);
813 } while (error == Z_BUF_ERROR);
815 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
821 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
822 for (t = 0; t < cols; t++) {
823 palette[t].r = data[pos++];
824 palette[t].g = data[pos++];
825 palette[t].b = data[pos++];
827 palette[t].a = data[pos++];
834 for (y = 0; y < height; y++) {
835 int srcwidth = width * (bpp / 8);
838 // 32 bit to 24 bit "conversion"
839 for (x = 0; x < width; x++) {
840 dest[pos2].r = data[pos + 1];
841 dest[pos2].g = data[pos + 2];
842 dest[pos2].b = data[pos + 3];
845 pos += 4; //ignore padding byte
848 for (x = 0; x < width; x++) {
849 /* TODO: premultiply alpha?
850 dest[pos2].r = (data[pos + 1]*255)/data[pos+0];
851 dest[pos2].g = (data[pos + 2]*255)/data[pos+0];
852 dest[pos2].b = (data[pos + 3]*255)/data[pos+0];
854 dest[pos2].r = data[pos + 1];
855 dest[pos2].g = data[pos + 2];
856 dest[pos2].b = data[pos + 3];
857 dest[pos2].a = data[pos + 0]; //alpha
863 for (x = 0; x < srcwidth; x++) {
864 dest[pos2] = palette[data[pos++]];
868 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
878 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
879 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
889 swf_SetU32(tag, 0); //placeholder
890 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
891 for (y = 0; y < height; y++) {
892 U8 scanline[3 * width];
894 for (x = 0; x < width; x++) {
895 scanline[p++] = bitmap[width * y + x].r;
896 scanline[p++] = bitmap[width * y + x].g;
897 scanline[p++] = bitmap[width * y + x].b;
899 swf_SetJPEGBitsLine(jpeg, scanline);
901 swf_SetJPEGBitsFinish(jpeg);
902 PUT32(&tag->data[pos], tag->len - pos - 4);
904 data = rfx_alloc(OUTBUFFER_SIZE);
905 memset(&zs, 0x00, sizeof(z_stream));
907 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
908 fprintf(stderr, "rfxswf: zlib compression failed");
913 zs.avail_out = OUTBUFFER_SIZE;
915 for (y = 0; y < height; y++) {
918 for (x = 0; x < width; x++) {
919 scanline[p++] = bitmap[width * y + x].a;
922 zs.next_in = scanline;
925 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
926 fprintf(stderr, "rfxswf: zlib compression failed");
929 if (zs.next_out != data) {
930 swf_SetBlock(tag, data, zs.next_out - data);
932 zs.avail_out = OUTBUFFER_SIZE;
941 int ret = deflate(&zs, Z_FINISH);
942 if (ret != Z_OK && ret != Z_STREAM_END) {
943 fprintf(stderr, "rfxswf: zlib compression failed");
946 if (zs.next_out != data) {
947 swf_SetBlock(tag, data, zs.next_out - data);
949 zs.avail_out = OUTBUFFER_SIZE;
951 if (ret == Z_STREAM_END) {
961 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
963 TAG *tag1 = 0, *tag2 = 0;
964 int has_alpha = swf_ImageHasAlpha(mem,width,height);
966 /* try lossless image */
967 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
968 swf_SetU16(tag1, bitid);
969 swf_SetLosslessImage(tag1, mem, width, height);
973 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
974 swf_SetU16(tag2, bitid);
975 swf_SetJPEGBits3(tag2, width, height, mem, quality);
977 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
978 swf_SetU16(tag2, bitid);
979 swf_SetJPEGBits2(tag2, width, height, mem, quality);
982 if(tag1 && tag1->len < tag2->len) {
983 /* use the zlib version- it's smaller */
985 if(tag) tag->next = tag1;
989 /* use the jpeg version- it's smaller */
991 if(tag) tag->next = tag2;
1000 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1003 if (tag->id == ST_DEFINEBITSJPEG ||
1004 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1006 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1008 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1012 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1013 tag->id == ST_DEFINEBITSLOSSLESS2) {
1015 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1017 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1021 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1022 swf_TagGetName(tag));
1026 #undef OUTBUFFER_SIZE
1029 void swf_RemoveJPEGTables(SWF * swf)
1031 TAG *tag = swf->firstTag;
1032 TAG *tables_tag = 0;
1034 if (tag->id == ST_JPEGTABLES) {
1043 tag = swf->firstTag;
1045 if (tag->id == ST_DEFINEBITSJPEG) {
1047 void *data = rfx_alloc(len);
1048 swf_GetBlock(tag, data, tag->len);
1049 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1050 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1051 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1052 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1057 if (swf->firstTag == tables_tag)
1058 swf->firstTag = tables_tag->next;
1059 swf_DeleteTag(tables_tag);
1062 typedef struct scale_lookup {
1064 unsigned int weight;
1067 typedef struct rgba_int {
1068 unsigned int r,g,b,a;
1071 static int bicubic = 0;
1073 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1075 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1076 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1077 double fx = ((double)width)/((double)newwidth);
1080 scale_lookup_t*p_x = lookupx;
1082 if(newwidth<=width) {
1083 for(x=0;x<newwidth;x++) {
1084 double ex = px + fx;
1085 int fromx = (int)px;
1087 double rem = fromx+1-px;
1088 int i = (int)(256/fx);
1089 int xweight = (int)(rem*256/fx);
1093 if(tox>=width) tox = width-1;
1094 for(xx=fromx;xx<=tox;xx++) {
1095 if(xx==fromx && xx==tox) p_x->weight = 256;
1096 else if(xx==fromx) p_x->weight = xweight;
1097 else if(xx==tox) p_x->weight = 256-w;
1098 else p_x->weight = i;
1106 for(x=0;x<newwidth;x++) {
1108 int ix2 = ((int)px)+1;
1110 if(ix2>=width) ix2=width-1;
1114 p_x[0].weight = (int)(256*(1-r));
1116 p_x[1].weight = 256-p_x[0].weight;
1122 lblockx[newwidth] = p_x;
1125 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1129 scale_lookup_t *p, **lblockx,**lblocky;
1132 if(newwidth<1 || newheight<1)
1135 /* this is bad because this scaler doesn't yet handle monochrome
1136 images with 2 colors in a way that the final image hasn't more
1138 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2)
1139 fprintf(stderr, "Warning: scaling monochrome image\n");
1141 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1142 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1144 lblockx = make_scale_lookup(width, newwidth);
1145 lblocky = make_scale_lookup(height, newheight);
1147 for(p=lblocky[0];p<lblocky[newheight];p++)
1150 for(y=0;y<newheight;y++) {
1151 RGBA*destline = &newdata[y*newwidth];
1153 /* create lookup table for y */
1154 rgba_int_t*l = tmpline;
1155 scale_lookup_t*p_y,*p_x;
1156 memset(tmpline, 0, width*sizeof(rgba_int_t));
1157 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1158 RGBA*line = &data[p_y->pos];
1160 int weight = p_y->weight;
1161 for(x=0;x<width;x++) {
1162 tmpline[x].r += line[x].r*weight;
1163 tmpline[x].g += line[x].g*weight;
1164 tmpline[x].b += line[x].b*weight;
1165 tmpline[x].a += line[x].a*weight;
1169 /* process x direction */
1171 for(x=0;x<newwidth;x++) {
1172 unsigned int r=0,g=0,b=0,a=0;
1173 scale_lookup_t*p_x_to = lblockx[x+1];
1175 rgba_int_t* col = &tmpline[p_x->pos];
1176 unsigned int weight = p_x->weight;
1182 } while (p_x<p_x_to);
1184 destline->r = r >> 16;
1185 destline->g = g >> 16;
1186 destline->b = b >> 16;
1187 destline->a = a >> 16;