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));
83 typedef struct _JPEGDESTMGR {
84 struct jpeg_destination_mgr mgr;
87 struct jpeg_compress_struct cinfo;
88 struct jpeg_error_mgr jerr;
89 } JPEGDESTMGR, *LPJPEGDESTMGR;
91 // Destination manager callbacks
93 static void RFXSWF_init_destination(j_compress_ptr cinfo)
95 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
96 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
97 dmgr->mgr.next_output_byte = dmgr->buffer;
98 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
101 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
103 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
104 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
105 dmgr->mgr.next_output_byte = dmgr->buffer;
106 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
110 static void RFXSWF_term_destination(j_compress_ptr cinfo)
112 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
113 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
114 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
115 rfx_free(dmgr->buffer);
116 dmgr->mgr.free_in_buffer = 0;
119 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
123 // redirect compression lib output to local SWF Tag structure
125 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
127 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
129 jpeg_create_compress(&jpeg->cinfo);
131 jpeg->mgr.init_destination = RFXSWF_init_destination;
132 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
133 jpeg->mgr.term_destination = RFXSWF_term_destination;
137 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
141 jpeg->cinfo.image_width = width;
142 jpeg->cinfo.image_height = height;
143 jpeg->cinfo.input_components = 3;
144 jpeg->cinfo.in_color_space = JCS_RGB;
146 jpeg_set_defaults(&jpeg->cinfo);
147 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
149 // write tables to SWF
151 jpeg_write_tables(&jpeg->cinfo);
153 // compess image to SWF
155 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
156 jpeg_start_compress(&jpeg->cinfo, FALSE);
158 return (JPEGBITS *) jpeg;
161 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
163 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
166 jpeg_write_scanlines(&jpeg->cinfo, data, n);
170 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
172 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
175 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
177 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
180 jpeg_finish_compress(&jpeg->cinfo);
185 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
190 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
191 for (y = 0; y < height; y++) {
192 U8 scanline[3 * width];
194 for (x = 0; x < width; x++) {
195 scanline[p++] = bitmap[width * y + x].r;
196 scanline[p++] = bitmap[width * y + x].g;
197 scanline[p++] = bitmap[width * y + x].b;
199 swf_SetJPEGBitsLine(jpeg, scanline);
201 swf_SetJPEGBitsFinish(jpeg);
204 void swf_GetJPEGSize(char *fname, int *width, int *height)
206 struct jpeg_decompress_struct cinfo;
207 struct jpeg_error_mgr jerr;
211 cinfo.err = jpeg_std_error(&jerr);
212 jpeg_create_decompress(&cinfo);
213 if ((fi = fopen(fname, "rb")) == NULL) {
214 fprintf(stderr, "rfxswf: file open error\n");
217 jpeg_stdio_src(&cinfo, fi);
218 jpeg_read_header(&cinfo, TRUE);
219 *width = cinfo.image_width;
220 *height = cinfo.image_height;
221 jpeg_destroy_decompress(&cinfo);
225 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
227 struct jpeg_decompress_struct cinfo;
228 struct jpeg_error_mgr jerr;
233 cinfo.err = jpeg_std_error(&jerr);
234 jpeg_create_decompress(&cinfo);
236 if ((f = fopen(fname, "rb")) == NULL) {
237 fprintf(stderr, "rfxswf: file open error\n");
241 jpeg_stdio_src(&cinfo, f);
242 jpeg_read_header(&cinfo, TRUE);
243 jpeg_start_decompress(&cinfo);
246 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
248 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
253 if (cinfo.out_color_space == JCS_GRAYSCALE) {
254 for (y = 0; y < cinfo.output_height; y++) {
256 jpeg_read_scanlines(&cinfo, &js, 1);
257 for (x = cinfo.output_width - 1; x >= 0; x--) {
258 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
260 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
262 } else if (cinfo.out_color_space == JCS_RGB) {
263 for (y = 0; y < cinfo.output_height; y++) {
264 jpeg_read_scanlines(&cinfo, &js, 1);
265 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
267 } else if (cinfo.out_color_space == JCS_YCCK) {
269 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
271 } else if (cinfo.out_color_space == JCS_YCbCr) {
272 for (y = 0; y < cinfo.output_height; y++) {
274 for (x = 0; x < cinfo.output_width; x++) {
275 int y = js[x * 3 + 0];
276 int u = js[x * 3 + 1];
277 int v = js[x * 3 + 1];
278 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
280 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
281 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
284 } else if (cinfo.out_color_space == JCS_CMYK) {
285 for (y = 0; y < cinfo.output_height; y++) {
287 jpeg_read_scanlines(&cinfo, &js, 1);
288 /* This routine seems to work for now-
289 It's a mixture of 3 different
290 CMYK->RGB conversion routines I found in the
291 web. (which all produced garbage)
292 I'm happily accepting suggestions. (mk) */
293 for (x = 0; x < cinfo.output_width; x++) {
294 int white = 255 - js[x * 4 + 3];
295 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
296 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
297 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
299 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
304 swf_SetJPEGBitsFinish(out);
305 jpeg_finish_decompress(&cinfo);
311 /* jpeg_source_mgr functions */
312 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
314 TAG *tag = (TAG *) cinfo->client_data;
315 swf_SetTagPos(tag, 2);
316 cinfo->src->bytes_in_buffer = 0;
318 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
320 TAG *tag = (TAG *) cinfo->client_data;
321 if (tag->data[tag->pos + 0] == 0xff &&
322 tag->data[tag->pos + 1] == 0xd9 &&
323 tag->data[tag->pos + 2] == 0xff &&
324 tag->data[tag->pos + 3] == 0xd8) {
327 if (tag->pos >= tag->len) {
328 cinfo->src->next_input_byte = 0;
329 cinfo->src->bytes_in_buffer = 0;
332 cinfo->src->next_input_byte = &tag->data[tag->pos];
333 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
337 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
339 TAG *tag = (TAG *) cinfo->client_data;
340 cinfo->src->next_input_byte = 0;
341 cinfo->src->bytes_in_buffer = 0;
344 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
346 return jpeg_resync_to_restart(cinfo, desired);
348 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
350 TAG *tag = (TAG *) cinfo->client_data;
352 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
354 struct jpeg_decompress_struct cinfo;
355 struct jpeg_error_mgr jerr;
356 struct jpeg_source_mgr mgr;
362 if (tag->id == ST_DEFINEBITSJPEG) {
364 "rfxswf: extracting from definebitsjpeg not yet supported");
367 if (tag->id == ST_DEFINEBITSJPEG3) {
369 "rfxswf: extracting from definebitsjpeg3 not yet supported");
373 cinfo.err = jpeg_std_error(&jerr);
374 jpeg_create_decompress(&cinfo);
376 cinfo.client_data = (void *) tag;
378 cinfo.src->init_source = tag_init_source;
379 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
380 cinfo.src->skip_input_data = tag_skip_input_data;
381 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
382 cinfo.src->term_source = tag_term_source;
383 cinfo.out_color_space = JCS_RGB;
385 jpeg_read_header(&cinfo, TRUE);
386 *width = cinfo.image_width;
387 *height = cinfo.image_height;
389 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
391 jpeg_start_decompress(&cinfo);
392 for (y = 0; y < cinfo.output_height; y++) {
393 RGBA *line = &dest[y * cinfo.image_width];
394 U8 *to = (U8 *) line;
396 jpeg_read_scanlines(&cinfo, &to, 1);
397 for (x = cinfo.output_width - 1; x >= 0; --x) {
398 int r = to[x * 3 + 0];
399 int g = to[x * 3 + 1];
400 int b = to[x * 3 + 2];
408 jpeg_finish_decompress(&cinfo);
410 jpeg_destroy_decompress(&cinfo);
414 #endif // HAVE_JPEGLIB
416 // Lossless compression texture based on zlib
420 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
422 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
424 zs->avail_out = OUTBUFFER_SIZE;
426 int status = deflate(zs, Z_NO_FLUSH);
428 if (status != Z_OK) {
429 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
434 if (zs->next_out != data) {
435 swf_SetBlock(t, data, zs->next_out - data);
437 zs->avail_out = OUTBUFFER_SIZE;
440 if (zs->avail_in == 0)
450 int status = deflate(zs, Z_FINISH);
451 if (status != Z_OK && status != Z_STREAM_END) {
452 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
457 if (zs->next_out != data) {
458 swf_SetBlock(t, data, zs->next_out - data);
460 zs->avail_out = OUTBUFFER_SIZE;
463 if (status == Z_STREAM_END)
471 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
476 switch (bitmap_flags) {
478 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
480 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
486 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
490 swf_SetU8(t, bitmap_flags);
491 swf_SetU16(t, width);
492 swf_SetU16(t, height);
497 memset(&zs, 0x00, sizeof(z_stream));
501 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
502 zs.avail_in = bps * height;
505 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
510 res = -3; // zlib error
515 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
518 int bps = BYTES_PER_SCANLINE(width);
521 if (!pal) // create default palette for grayscale images
524 pal = rfx_alloc(256 * sizeof(RGBA));
525 for (i = 0; i < 256; i++) {
526 pal[i].r = pal[i].g = pal[i].b = i;
532 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
533 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
535 return -1; // parameter error
538 swf_SetU8(t, BMF_8BIT);
539 swf_SetU16(t, width);
540 swf_SetU16(t, height);
541 swf_SetU8(t, ncolors - 1); // number of pal entries
546 memset(&zs, 0x00, sizeof(z_stream));
550 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
551 U8 *zpal; // compress palette
552 if ((zpal = rfx_alloc(ncolors * 4))) {
556 /* be careful with ST_DEFINEBITSLOSSLESS2, because
557 the Flash player produces great bugs if you use too many
558 alpha colors in your palette. The only sensible result that
559 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
560 make transparent parts in sprites. That's the cause why alpha
561 handling is implemented in lossless routines of rfxswf.
563 Indeed: I haven't understood yet how flash player handles
564 alpha values different from 0 and 0xff in lossless bitmaps...
567 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
569 for (i = 0; i < ncolors; i++) {
576 zs.avail_in = 4 * ncolors;
578 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
585 zs.avail_in = 3 * ncolors;
590 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
595 zs.avail_in = (bps * height * sizeof(U8));
597 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
604 res = -2; // memory error
606 res = -3; // zlib error
615 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
617 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
620 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
622 int hasalpha = swf_ImageHasAlpha(data, width, height);
624 tag->id = ST_DEFINEBITSLOSSLESS;
626 tag->id = ST_DEFINEBITSLOSSLESS2;
627 /* TODO: premultiply alpha? */
629 int num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
630 if(num>1 && num<=256) {
631 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
632 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
633 int width2 = BYTES_PER_SCANLINE(width);
634 U8*data2 = (U8*)malloc(width2*height);
635 int len = width*height;
638 for(y=0;y<height;y++) {
639 RGBA*src = &data[width*y];
640 U8*dest = &data2[width2*y];
641 for(x=0;x<width;x++) {
644 if(*(U32*)&col == *(U32*)&palette[r]) {
650 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
651 col.r, col.g, col.b, col.a, num);
656 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
660 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
664 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
666 int id, format, height, width, pos;
667 U32 datalen, datalen2;
672 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
677 if (tag->id != ST_DEFINEBITSLOSSLESS &&
678 tag->id != ST_DEFINEBITSLOSSLESS2) {
679 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
683 swf_SetTagPos(tag, 0);
684 id = swf_GetU16(tag);
685 format = swf_GetU8(tag);
692 if (format != 3 && format != 5) {
695 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
698 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
702 *dwidth = width = swf_GetU16(tag);
703 *dheight = height = swf_GetU16(tag);
705 dest = rfx_alloc(sizeof(RGBA) * width * height);
708 cols = swf_GetU8(tag) + 1;
713 datalen = (width * height * bpp / 8 + cols * 8);
718 data = rfx_alloc(datalen);
720 uncompress(data, &datalen, &tag->data[tag->pos],
721 tag->len - tag->pos);
722 } while (error == Z_BUF_ERROR);
724 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
730 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
731 for (t = 0; t < cols; t++) {
732 palette[t].r = data[pos++];
733 palette[t].g = data[pos++];
734 palette[t].b = data[pos++];
736 palette[t].a = data[pos++];
741 for (y = 0; y < height; y++) {
742 int srcwidth = width * (bpp / 8);
745 // 32 bit to 24 bit "conversion"
746 for (x = 0; x < width; x++) {
747 dest[pos2].r = data[pos + 1];
748 dest[pos2].g = data[pos + 2];
749 dest[pos2].b = data[pos + 3];
752 pos += 4; //ignore padding byte
755 for (x = 0; x < width; x++) {
756 /* TODO: un-premultiply alpha? */
757 dest[pos2].r = data[pos + 1];
758 dest[pos2].g = data[pos + 2];
759 dest[pos2].b = data[pos + 3];
760 dest[pos2].a = data[pos + 0]; //alpha
766 for (x = 0; x < srcwidth; x++) {
767 dest[pos2] = palette[data[pos++]];
771 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
781 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
782 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
792 swf_SetU32(tag, 0); //placeholder
793 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
794 for (y = 0; y < height; y++) {
795 U8 scanline[3 * width];
797 for (x = 0; x < width; x++) {
798 scanline[p++] = bitmap[width * y + x].r;
799 scanline[p++] = bitmap[width * y + x].g;
800 scanline[p++] = bitmap[width * y + x].b;
802 swf_SetJPEGBitsLine(jpeg, scanline);
804 swf_SetJPEGBitsFinish(jpeg);
805 PUT32(&tag->data[pos], tag->len - pos - 4);
807 data = rfx_alloc(OUTBUFFER_SIZE);
808 memset(&zs, 0x00, sizeof(z_stream));
810 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
811 fprintf(stderr, "rfxswf: zlib compression failed");
816 zs.avail_out = OUTBUFFER_SIZE;
818 for (y = 0; y < height; y++) {
821 for (x = 0; x < width; x++) {
822 scanline[p++] = bitmap[width * y + x].a;
825 zs.next_in = scanline;
828 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
829 fprintf(stderr, "rfxswf: zlib compression failed");
832 if (zs.next_out != data) {
833 swf_SetBlock(tag, data, zs.next_out - data);
835 zs.avail_out = OUTBUFFER_SIZE;
844 int ret = deflate(&zs, Z_FINISH);
845 if (ret != Z_OK && ret != Z_STREAM_END) {
846 fprintf(stderr, "rfxswf: zlib compression failed");
849 if (zs.next_out != data) {
850 swf_SetBlock(tag, data, zs.next_out - data);
852 zs.avail_out = OUTBUFFER_SIZE;
854 if (ret == Z_STREAM_END) {
864 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
866 TAG *tag1 = 0, *tag2 = 0;
867 int has_alpha = swf_ImageHasAlpha(mem,width,height);
869 /* try lossless image */
870 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
871 swf_SetU16(tag1, bitid);
872 swf_SetLosslessImage(tag1, mem, width, height);
876 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
877 swf_SetU16(tag2, bitid);
878 swf_SetJPEGBits3(tag2, width, height, mem, quality);
880 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
881 swf_SetU16(tag2, bitid);
882 swf_SetJPEGBits2(tag2, width, height, mem, quality);
885 if(tag1 && tag1->len < tag2->len) {
886 /* use the zlib version- it's smaller */
888 if(tag) tag->next = tag1;
892 /* use the jpeg version- it's smaller */
894 if(tag) tag->next = tag2;
903 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
906 if (tag->id == ST_DEFINEBITSJPEG ||
907 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
909 return swf_JPEG2TagToImage(tag, dwidth, dheight);
911 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
915 if (tag->id == ST_DEFINEBITSLOSSLESS ||
916 tag->id == ST_DEFINEBITSLOSSLESS2) {
918 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
920 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
924 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
925 swf_TagGetName(tag));
929 #undef OUTBUFFER_SIZE
932 void swf_RemoveJPEGTables(SWF * swf)
934 TAG *tag = swf->firstTag;
937 if (tag->id == ST_JPEGTABLES) {
948 if (tag->id == ST_DEFINEBITSJPEG) {
949 void *data = rfx_alloc(tag->len);
950 swf_GetBlock(tag, data, tag->len);
951 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
952 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
953 swf_SetBlock(tag, data, tag->len);
958 if (swf->firstTag == tables_tag)
959 swf->firstTag = tables_tag->next;
960 swf_DeleteTag(tables_tag);
963 typedef struct scale_lookup {
968 typedef struct rgba_int {
969 unsigned int r,g,b,a;
972 static int bicubic = 0;
974 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
976 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
977 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
978 double fx = ((double)width)/((double)newwidth);
981 scale_lookup_t*p_x = lookupx;
983 if(newwidth<=width) {
984 for(x=0;x<newwidth;x++) {
989 double rem = fromx+1-px;
990 int i = (int)(256/fx);
991 int xweight = (int)(rem*256/fx);
994 if(tox>=width) tox = width-1;
995 for(xx=fromx;xx<=tox;xx++) {
996 if(xx==fromx && xx==tox) p_x->weight = 256;
997 else if(xx==fromx) p_x->weight = xweight;
998 else if(xx==tox) p_x->weight = 256-w;
999 else p_x->weight = i;
1007 for(x=0;x<newwidth;x++) {
1010 int ix2 = ((int)px)+1;
1011 if(ix2>=width) ix2=width-1;
1015 p_x[0].weight = (int)(256*(1-r));
1017 p_x[1].weight = 256-p_x[0].weight;
1023 lblockx[newwidth] = p_x;
1027 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1029 if(newwidth<1 || newheight<1)
1032 RGBA* newdata= (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1033 scale_lookup_t *p, **lblockx,**lblocky;
1034 rgba_int_t*tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1036 lblockx = make_scale_lookup(width, newwidth);
1037 lblocky = make_scale_lookup(height, newheight);
1039 for(p=lblocky[0];p<lblocky[newheight];p++)
1042 for(y=0;y<newheight;y++) {
1043 RGBA*destline = &newdata[y*newwidth];
1045 /* create lookup table for y */
1046 rgba_int_t*l = tmpline;
1048 memset(tmpline, 0, width*sizeof(rgba_int_t));
1049 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1050 RGBA*line = &data[p_y->pos];
1052 int weight = p_y->weight;
1053 for(x=0;x<width;x++) {
1054 tmpline[x].r += line[x].r*weight;
1055 tmpline[x].g += line[x].g*weight;
1056 tmpline[x].b += line[x].b*weight;
1057 tmpline[x].a += line[x].a*weight;
1061 /* process x direction */
1062 scale_lookup_t*p_x = lblockx[0];
1063 for(x=0;x<newwidth;x++) {
1064 unsigned int r=0,g=0,b=0,a=0;
1065 scale_lookup_t*p_x_to = lblockx[x+1];
1067 rgba_int_t* col = &tmpline[p_x->pos];
1068 unsigned int weight = p_x->weight;
1074 } while (p_x<p_x_to);
1076 destline->r = r >> 16;
1077 destline->g = g >> 16;
1078 destline->b = b >> 16;
1079 destline->a = a >> 16;