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_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
42 int len = width*height;
47 int palette_overflow = 0;
50 if(sizeof(RGBA)!=sizeof(U32))
51 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
53 lastcol32 = pal32[palsize++] = *(U32*)&img[0];
57 U32 col32 = *(U32*)&img[t];
61 for(i=0;i<palsize;i++) {
70 pal32[palsize++] = col32;
77 memcpy(palette, pal, palsize*sizeof(RGBA));
81 int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
83 int len = width*height;
88 int palette_overflow = 0;
91 pal = malloc(65536*sizeof(U32));
93 memset(size, 0, sizeof(size));
95 if(sizeof(RGBA)!=sizeof(U32))
96 fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
98 lastcol32 = (*(U32*)&img[0])^0xffffffff; // don't match
102 U32 col32 = *(U32*)&img[t];
107 if(col32 == lastcol32)
109 hash = (col32 >> 17) ^ col32;
110 hash ^= ((hash>>8) + 1) ^ hash;
114 cpal = &pal[hash*256];
115 for(i=0;i<csize;i++) {
121 palette_overflow = 1;
124 cpal[size[hash]++] = col32;
136 U32* cpal = &pal[t*256];
138 palette[i++] = *(RGBA*)(&cpal[s]);
149 typedef struct _JPEGDESTMGR {
150 struct jpeg_destination_mgr mgr;
153 struct jpeg_compress_struct cinfo;
154 struct jpeg_error_mgr jerr;
155 } JPEGDESTMGR, *LPJPEGDESTMGR;
157 // Destination manager callbacks
159 static void RFXSWF_init_destination(j_compress_ptr cinfo)
161 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
162 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
163 dmgr->mgr.next_output_byte = dmgr->buffer;
164 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
167 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
169 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
170 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
171 dmgr->mgr.next_output_byte = dmgr->buffer;
172 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
176 static void RFXSWF_term_destination(j_compress_ptr cinfo)
178 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
179 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
180 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
181 rfx_free(dmgr->buffer);
182 dmgr->mgr.free_in_buffer = 0;
185 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
189 // redirect compression lib output to local SWF Tag structure
191 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
193 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
195 jpeg_create_compress(&jpeg->cinfo);
197 jpeg->mgr.init_destination = RFXSWF_init_destination;
198 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
199 jpeg->mgr.term_destination = RFXSWF_term_destination;
203 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
207 jpeg->cinfo.image_width = width;
208 jpeg->cinfo.image_height = height;
209 jpeg->cinfo.input_components = 3;
210 jpeg->cinfo.in_color_space = JCS_RGB;
212 jpeg_set_defaults(&jpeg->cinfo);
213 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
215 // write tables to SWF
217 jpeg_write_tables(&jpeg->cinfo);
219 // compess image to SWF
221 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
222 jpeg_start_compress(&jpeg->cinfo, FALSE);
224 return (JPEGBITS *) jpeg;
227 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
229 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
232 jpeg_write_scanlines(&jpeg->cinfo, data, n);
236 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
238 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
241 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
243 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
246 jpeg_finish_compress(&jpeg->cinfo);
251 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
256 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
257 for (y = 0; y < height; y++) {
258 U8 scanline[3 * width];
260 for (x = 0; x < width; x++) {
261 scanline[p++] = bitmap[width * y + x].r;
262 scanline[p++] = bitmap[width * y + x].g;
263 scanline[p++] = bitmap[width * y + x].b;
265 swf_SetJPEGBitsLine(jpeg, scanline);
267 swf_SetJPEGBitsFinish(jpeg);
270 void swf_GetJPEGSize(char *fname, int *width, int *height)
272 struct jpeg_decompress_struct cinfo;
273 struct jpeg_error_mgr jerr;
277 cinfo.err = jpeg_std_error(&jerr);
278 jpeg_create_decompress(&cinfo);
279 if ((fi = fopen(fname, "rb")) == NULL) {
280 fprintf(stderr, "rfxswf: file open error\n");
283 jpeg_stdio_src(&cinfo, fi);
284 jpeg_read_header(&cinfo, TRUE);
285 *width = cinfo.image_width;
286 *height = cinfo.image_height;
287 jpeg_destroy_decompress(&cinfo);
291 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
293 struct jpeg_decompress_struct cinfo;
294 struct jpeg_error_mgr jerr;
299 cinfo.err = jpeg_std_error(&jerr);
300 jpeg_create_decompress(&cinfo);
302 if ((f = fopen(fname, "rb")) == NULL) {
303 fprintf(stderr, "rfxswf: file open error\n");
307 jpeg_stdio_src(&cinfo, f);
308 jpeg_read_header(&cinfo, TRUE);
309 jpeg_start_decompress(&cinfo);
312 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
314 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
319 if (cinfo.out_color_space == JCS_GRAYSCALE) {
320 for (y = 0; y < cinfo.output_height; y++) {
322 jpeg_read_scanlines(&cinfo, &js, 1);
323 for (x = cinfo.output_width - 1; x >= 0; x--) {
324 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
326 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
328 } else if (cinfo.out_color_space == JCS_RGB) {
329 for (y = 0; y < cinfo.output_height; y++) {
330 jpeg_read_scanlines(&cinfo, &js, 1);
331 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
333 } else if (cinfo.out_color_space == JCS_YCCK) {
335 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
337 } else if (cinfo.out_color_space == JCS_YCbCr) {
338 for (y = 0; y < cinfo.output_height; y++) {
340 for (x = 0; x < cinfo.output_width; x++) {
341 int y = js[x * 3 + 0];
342 int u = js[x * 3 + 1];
343 int v = js[x * 3 + 1];
344 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
346 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
347 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
350 } else if (cinfo.out_color_space == JCS_CMYK) {
351 for (y = 0; y < cinfo.output_height; y++) {
353 jpeg_read_scanlines(&cinfo, &js, 1);
354 /* This routine seems to work for now-
355 It's a mixture of 3 different
356 CMYK->RGB conversion routines I found in the
357 web. (which all produced garbage)
358 I'm happily accepting suggestions. (mk) */
359 for (x = 0; x < cinfo.output_width; x++) {
360 int white = 255 - js[x * 4 + 3];
361 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
362 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
363 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
365 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
370 swf_SetJPEGBitsFinish(out);
371 jpeg_finish_decompress(&cinfo);
377 /* jpeg_source_mgr functions */
378 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
380 TAG *tag = (TAG *) cinfo->client_data;
381 swf_SetTagPos(tag, 2);
382 cinfo->src->bytes_in_buffer = 0;
384 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
386 TAG *tag = (TAG *) cinfo->client_data;
387 if (tag->data[tag->pos + 0] == 0xff &&
388 tag->data[tag->pos + 1] == 0xd9 &&
389 tag->data[tag->pos + 2] == 0xff &&
390 tag->data[tag->pos + 3] == 0xd8) {
393 if (tag->pos >= tag->len) {
394 cinfo->src->next_input_byte = 0;
395 cinfo->src->bytes_in_buffer = 0;
398 cinfo->src->next_input_byte = &tag->data[tag->pos];
399 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
403 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
405 TAG *tag = (TAG *) cinfo->client_data;
406 cinfo->src->next_input_byte = 0;
407 cinfo->src->bytes_in_buffer = 0;
410 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
412 return jpeg_resync_to_restart(cinfo, desired);
414 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
416 TAG *tag = (TAG *) cinfo->client_data;
418 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
420 struct jpeg_decompress_struct cinfo;
421 struct jpeg_error_mgr jerr;
422 struct jpeg_source_mgr mgr;
428 if (tag->id == ST_DEFINEBITSJPEG) {
430 "rfxswf: extracting from definebitsjpeg not yet supported");
433 if (tag->id == ST_DEFINEBITSJPEG3) {
435 "rfxswf: extracting from definebitsjpeg3 not yet supported");
439 cinfo.err = jpeg_std_error(&jerr);
440 jpeg_create_decompress(&cinfo);
442 cinfo.client_data = (void *) tag;
444 cinfo.src->init_source = tag_init_source;
445 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
446 cinfo.src->skip_input_data = tag_skip_input_data;
447 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
448 cinfo.src->term_source = tag_term_source;
449 cinfo.out_color_space = JCS_RGB;
451 jpeg_read_header(&cinfo, TRUE);
452 *width = cinfo.image_width;
453 *height = cinfo.image_height;
455 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
457 jpeg_start_decompress(&cinfo);
458 for (y = 0; y < cinfo.output_height; y++) {
459 RGBA *line = &dest[y * cinfo.image_width];
460 U8 *to = (U8 *) line;
462 jpeg_read_scanlines(&cinfo, &to, 1);
463 for (x = cinfo.output_width - 1; x >= 0; --x) {
464 int r = to[x * 3 + 0];
465 int g = to[x * 3 + 1];
466 int b = to[x * 3 + 2];
474 jpeg_finish_decompress(&cinfo);
476 jpeg_destroy_decompress(&cinfo);
480 #endif // HAVE_JPEGLIB
482 // Lossless compression texture based on zlib
486 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
488 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
490 zs->avail_out = OUTBUFFER_SIZE;
492 int status = deflate(zs, Z_NO_FLUSH);
494 if (status != Z_OK) {
495 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
500 if (zs->next_out != data) {
501 swf_SetBlock(t, data, zs->next_out - data);
503 zs->avail_out = OUTBUFFER_SIZE;
506 if (zs->avail_in == 0)
516 int status = deflate(zs, Z_FINISH);
517 if (status != Z_OK && status != Z_STREAM_END) {
518 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
523 if (zs->next_out != data) {
524 swf_SetBlock(t, data, zs->next_out - data);
526 zs->avail_out = OUTBUFFER_SIZE;
529 if (status == Z_STREAM_END)
537 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
542 switch (bitmap_flags) {
544 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
546 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
552 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
556 swf_SetU8(t, bitmap_flags);
557 swf_SetU16(t, width);
558 swf_SetU16(t, height);
563 memset(&zs, 0x00, sizeof(z_stream));
567 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
568 zs.avail_in = bps * height;
571 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
576 res = -3; // zlib error
581 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
584 int bps = BYTES_PER_SCANLINE(width);
587 if (!pal) // create default palette for grayscale images
590 pal = rfx_alloc(256 * sizeof(RGBA));
591 for (i = 0; i < 256; i++) {
592 pal[i].r = pal[i].g = pal[i].b = i;
598 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
599 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
601 return -1; // parameter error
604 swf_SetU8(t, BMF_8BIT);
605 swf_SetU16(t, width);
606 swf_SetU16(t, height);
607 swf_SetU8(t, ncolors - 1); // number of pal entries
612 memset(&zs, 0x00, sizeof(z_stream));
616 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
617 U8 *zpal; // compress palette
618 if ((zpal = rfx_alloc(ncolors * 4))) {
622 /* be careful with ST_DEFINEBITSLOSSLESS2, because
623 the Flash player produces great bugs if you use too many
624 alpha colors in your palette. The only sensible result that
625 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
626 make transparent parts in sprites. That's the cause why alpha
627 handling is implemented in lossless routines of rfxswf.
629 Indeed: I haven't understood yet how flash player handles
630 alpha values different from 0 and 0xff in lossless bitmaps...
633 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
635 for (i = 0; i < ncolors; i++) {
642 zs.avail_in = 4 * ncolors;
644 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
651 zs.avail_in = 3 * ncolors;
656 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
661 zs.avail_in = (bps * height * sizeof(U8));
663 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
670 res = -2; // memory error
672 res = -3; // zlib error
681 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
683 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
686 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
688 int hasalpha = swf_ImageHasAlpha(data, width, height);
691 tag->id = ST_DEFINEBITSLOSSLESS;
693 tag->id = ST_DEFINEBITSLOSSLESS2;
694 /* TODO: premultiply alpha? */
696 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
697 if(num>1 && num<=256) {
698 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
699 int width2 = BYTES_PER_SCANLINE(width);
700 U8*data2 = (U8*)malloc(width2*height);
701 int len = width*height;
704 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
705 for(y=0;y<height;y++) {
706 RGBA*src = &data[width*y];
707 U8*dest = &data2[width2*y];
708 for(x=0;x<width;x++) {
711 if(*(U32*)&col == *(U32*)&palette[r]) {
717 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
718 col.r, col.g, col.b, col.a, num);
723 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
727 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
731 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
733 int id, format, height, width, pos;
734 U32 datalen, datalen2;
739 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
744 if (tag->id != ST_DEFINEBITSLOSSLESS &&
745 tag->id != ST_DEFINEBITSLOSSLESS2) {
746 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
750 swf_SetTagPos(tag, 0);
751 id = swf_GetU16(tag);
752 format = swf_GetU8(tag);
759 if (format != 3 && format != 5) {
762 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
765 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
769 *dwidth = width = swf_GetU16(tag);
770 *dheight = height = swf_GetU16(tag);
772 dest = rfx_alloc(sizeof(RGBA) * width * height);
775 cols = swf_GetU8(tag) + 1;
780 datalen = (width * height * bpp / 8 + cols * 8);
785 data = rfx_alloc(datalen);
787 uncompress(data, &datalen, &tag->data[tag->pos],
788 tag->len - tag->pos);
789 } while (error == Z_BUF_ERROR);
791 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
797 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
798 for (t = 0; t < cols; t++) {
799 palette[t].r = data[pos++];
800 palette[t].g = data[pos++];
801 palette[t].b = data[pos++];
803 palette[t].a = data[pos++];
808 for (y = 0; y < height; y++) {
809 int srcwidth = width * (bpp / 8);
812 // 32 bit to 24 bit "conversion"
813 for (x = 0; x < width; x++) {
814 dest[pos2].r = data[pos + 1];
815 dest[pos2].g = data[pos + 2];
816 dest[pos2].b = data[pos + 3];
819 pos += 4; //ignore padding byte
822 for (x = 0; x < width; x++) {
823 /* TODO: un-premultiply alpha? */
824 dest[pos2].r = data[pos + 1];
825 dest[pos2].g = data[pos + 2];
826 dest[pos2].b = data[pos + 3];
827 dest[pos2].a = data[pos + 0]; //alpha
833 for (x = 0; x < srcwidth; x++) {
834 dest[pos2] = palette[data[pos++]];
838 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
848 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
849 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
859 swf_SetU32(tag, 0); //placeholder
860 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
861 for (y = 0; y < height; y++) {
862 U8 scanline[3 * width];
864 for (x = 0; x < width; x++) {
865 scanline[p++] = bitmap[width * y + x].r;
866 scanline[p++] = bitmap[width * y + x].g;
867 scanline[p++] = bitmap[width * y + x].b;
869 swf_SetJPEGBitsLine(jpeg, scanline);
871 swf_SetJPEGBitsFinish(jpeg);
872 PUT32(&tag->data[pos], tag->len - pos - 4);
874 data = rfx_alloc(OUTBUFFER_SIZE);
875 memset(&zs, 0x00, sizeof(z_stream));
877 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
878 fprintf(stderr, "rfxswf: zlib compression failed");
883 zs.avail_out = OUTBUFFER_SIZE;
885 for (y = 0; y < height; y++) {
888 for (x = 0; x < width; x++) {
889 scanline[p++] = bitmap[width * y + x].a;
892 zs.next_in = scanline;
895 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
896 fprintf(stderr, "rfxswf: zlib compression failed");
899 if (zs.next_out != data) {
900 swf_SetBlock(tag, data, zs.next_out - data);
902 zs.avail_out = OUTBUFFER_SIZE;
911 int ret = deflate(&zs, Z_FINISH);
912 if (ret != Z_OK && ret != Z_STREAM_END) {
913 fprintf(stderr, "rfxswf: zlib compression failed");
916 if (zs.next_out != data) {
917 swf_SetBlock(tag, data, zs.next_out - data);
919 zs.avail_out = OUTBUFFER_SIZE;
921 if (ret == Z_STREAM_END) {
931 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
933 TAG *tag1 = 0, *tag2 = 0;
934 int has_alpha = swf_ImageHasAlpha(mem,width,height);
936 /* try lossless image */
937 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
938 swf_SetU16(tag1, bitid);
939 swf_SetLosslessImage(tag1, mem, width, height);
943 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
944 swf_SetU16(tag2, bitid);
945 swf_SetJPEGBits3(tag2, width, height, mem, quality);
947 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
948 swf_SetU16(tag2, bitid);
949 swf_SetJPEGBits2(tag2, width, height, mem, quality);
952 if(tag1 && tag1->len < tag2->len) {
953 /* use the zlib version- it's smaller */
955 if(tag) tag->next = tag1;
959 /* use the jpeg version- it's smaller */
961 if(tag) tag->next = tag2;
970 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
973 if (tag->id == ST_DEFINEBITSJPEG ||
974 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
976 return swf_JPEG2TagToImage(tag, dwidth, dheight);
978 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
982 if (tag->id == ST_DEFINEBITSLOSSLESS ||
983 tag->id == ST_DEFINEBITSLOSSLESS2) {
985 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
987 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
991 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
992 swf_TagGetName(tag));
996 #undef OUTBUFFER_SIZE
999 void swf_RemoveJPEGTables(SWF * swf)
1001 TAG *tag = swf->firstTag;
1002 TAG *tables_tag = 0;
1004 if (tag->id == ST_JPEGTABLES) {
1013 tag = swf->firstTag;
1015 if (tag->id == ST_DEFINEBITSJPEG) {
1016 void *data = rfx_alloc(tag->len);
1017 swf_GetBlock(tag, data, tag->len);
1018 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1019 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1020 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1021 swf_SetBlock(tag, &((U8*)data)[2], tag->len-2);
1026 if (swf->firstTag == tables_tag)
1027 swf->firstTag = tables_tag->next;
1028 swf_DeleteTag(tables_tag);
1031 typedef struct scale_lookup {
1033 unsigned int weight;
1036 typedef struct rgba_int {
1037 unsigned int r,g,b,a;
1040 static int bicubic = 0;
1042 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1044 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1045 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1046 double fx = ((double)width)/((double)newwidth);
1049 scale_lookup_t*p_x = lookupx;
1051 if(newwidth<=width) {
1052 for(x=0;x<newwidth;x++) {
1053 double ex = px + fx;
1054 int fromx = (int)px;
1056 double rem = fromx+1-px;
1057 int i = (int)(256/fx);
1058 int xweight = (int)(rem*256/fx);
1062 if(tox>=width) tox = width-1;
1063 for(xx=fromx;xx<=tox;xx++) {
1064 if(xx==fromx && xx==tox) p_x->weight = 256;
1065 else if(xx==fromx) p_x->weight = xweight;
1066 else if(xx==tox) p_x->weight = 256-w;
1067 else p_x->weight = i;
1075 for(x=0;x<newwidth;x++) {
1077 int ix2 = ((int)px)+1;
1079 if(ix2>=width) ix2=width-1;
1083 p_x[0].weight = (int)(256*(1-r));
1085 p_x[1].weight = 256-p_x[0].weight;
1091 lblockx[newwidth] = p_x;
1095 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1099 scale_lookup_t *p, **lblockx,**lblocky;
1102 if(newwidth<1 || newheight<1)
1105 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1106 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1108 lblockx = make_scale_lookup(width, newwidth);
1109 lblocky = make_scale_lookup(height, newheight);
1111 for(p=lblocky[0];p<lblocky[newheight];p++)
1114 for(y=0;y<newheight;y++) {
1115 RGBA*destline = &newdata[y*newwidth];
1117 /* create lookup table for y */
1118 rgba_int_t*l = tmpline;
1119 scale_lookup_t*p_y,*p_x;
1120 memset(tmpline, 0, width*sizeof(rgba_int_t));
1121 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1122 RGBA*line = &data[p_y->pos];
1124 int weight = p_y->weight;
1125 for(x=0;x<width;x++) {
1126 tmpline[x].r += line[x].r*weight;
1127 tmpline[x].g += line[x].g*weight;
1128 tmpline[x].b += line[x].b*weight;
1129 tmpline[x].a += line[x].a*weight;
1133 /* process x direction */
1135 for(x=0;x<newwidth;x++) {
1136 unsigned int r=0,g=0,b=0,a=0;
1137 scale_lookup_t*p_x_to = lblockx[x+1];
1139 rgba_int_t* col = &tmpline[p_x->pos];
1140 unsigned int weight = p_x->weight;
1146 } while (p_x<p_x_to);
1148 destline->r = r >> 16;
1149 destline->g = g >> 16;
1150 destline->b = b >> 16;
1151 destline->a = a >> 16;