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++];
810 for (y = 0; y < height; y++) {
811 int srcwidth = width * (bpp / 8);
814 // 32 bit to 24 bit "conversion"
815 for (x = 0; x < width; x++) {
816 dest[pos2].r = data[pos + 1];
817 dest[pos2].g = data[pos + 2];
818 dest[pos2].b = data[pos + 3];
821 pos += 4; //ignore padding byte
824 for (x = 0; x < width; x++) {
825 /* TODO: premultiply alpha?
826 dest[pos2].r = (data[pos + 1]*255)/data[pos+0];
827 dest[pos2].g = (data[pos + 2]*255)/data[pos+0];
828 dest[pos2].b = (data[pos + 3]*255)/data[pos+0];
830 dest[pos2].r = data[pos + 1];
831 dest[pos2].g = data[pos + 2];
832 dest[pos2].b = data[pos + 3];
833 dest[pos2].a = data[pos + 0]; //alpha
839 for (x = 0; x < srcwidth; x++) {
840 dest[pos2] = palette[data[pos++]];
844 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
854 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
855 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
865 swf_SetU32(tag, 0); //placeholder
866 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
867 for (y = 0; y < height; y++) {
868 U8 scanline[3 * width];
870 for (x = 0; x < width; x++) {
871 scanline[p++] = bitmap[width * y + x].r;
872 scanline[p++] = bitmap[width * y + x].g;
873 scanline[p++] = bitmap[width * y + x].b;
875 swf_SetJPEGBitsLine(jpeg, scanline);
877 swf_SetJPEGBitsFinish(jpeg);
878 PUT32(&tag->data[pos], tag->len - pos - 4);
880 data = rfx_alloc(OUTBUFFER_SIZE);
881 memset(&zs, 0x00, sizeof(z_stream));
883 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
884 fprintf(stderr, "rfxswf: zlib compression failed");
889 zs.avail_out = OUTBUFFER_SIZE;
891 for (y = 0; y < height; y++) {
894 for (x = 0; x < width; x++) {
895 scanline[p++] = bitmap[width * y + x].a;
898 zs.next_in = scanline;
901 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
902 fprintf(stderr, "rfxswf: zlib compression failed");
905 if (zs.next_out != data) {
906 swf_SetBlock(tag, data, zs.next_out - data);
908 zs.avail_out = OUTBUFFER_SIZE;
917 int ret = deflate(&zs, Z_FINISH);
918 if (ret != Z_OK && ret != Z_STREAM_END) {
919 fprintf(stderr, "rfxswf: zlib compression failed");
922 if (zs.next_out != data) {
923 swf_SetBlock(tag, data, zs.next_out - data);
925 zs.avail_out = OUTBUFFER_SIZE;
927 if (ret == Z_STREAM_END) {
937 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
939 TAG *tag1 = 0, *tag2 = 0;
940 int has_alpha = swf_ImageHasAlpha(mem,width,height);
942 /* try lossless image */
943 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
944 swf_SetU16(tag1, bitid);
945 swf_SetLosslessImage(tag1, mem, width, height);
949 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
950 swf_SetU16(tag2, bitid);
951 swf_SetJPEGBits3(tag2, width, height, mem, quality);
953 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
954 swf_SetU16(tag2, bitid);
955 swf_SetJPEGBits2(tag2, width, height, mem, quality);
958 if(tag1 && tag1->len < tag2->len) {
959 /* use the zlib version- it's smaller */
961 if(tag) tag->next = tag1;
965 /* use the jpeg version- it's smaller */
967 if(tag) tag->next = tag2;
976 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
979 if (tag->id == ST_DEFINEBITSJPEG ||
980 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
982 return swf_JPEG2TagToImage(tag, dwidth, dheight);
984 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
988 if (tag->id == ST_DEFINEBITSLOSSLESS ||
989 tag->id == ST_DEFINEBITSLOSSLESS2) {
991 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
993 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
997 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
998 swf_TagGetName(tag));
1002 #undef OUTBUFFER_SIZE
1005 void swf_RemoveJPEGTables(SWF * swf)
1007 TAG *tag = swf->firstTag;
1008 TAG *tables_tag = 0;
1010 if (tag->id == ST_JPEGTABLES) {
1019 tag = swf->firstTag;
1021 if (tag->id == ST_DEFINEBITSJPEG) {
1022 void *data = rfx_alloc(tag->len);
1023 swf_GetBlock(tag, data, tag->len);
1024 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1025 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1026 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1027 swf_SetBlock(tag, &((U8*)data)[2], tag->len-2);
1032 if (swf->firstTag == tables_tag)
1033 swf->firstTag = tables_tag->next;
1034 swf_DeleteTag(tables_tag);
1037 typedef struct scale_lookup {
1039 unsigned int weight;
1042 typedef struct rgba_int {
1043 unsigned int r,g,b,a;
1046 static int bicubic = 0;
1048 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1050 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1051 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1052 double fx = ((double)width)/((double)newwidth);
1055 scale_lookup_t*p_x = lookupx;
1057 if(newwidth<=width) {
1058 for(x=0;x<newwidth;x++) {
1059 double ex = px + fx;
1060 int fromx = (int)px;
1062 double rem = fromx+1-px;
1063 int i = (int)(256/fx);
1064 int xweight = (int)(rem*256/fx);
1068 if(tox>=width) tox = width-1;
1069 for(xx=fromx;xx<=tox;xx++) {
1070 if(xx==fromx && xx==tox) p_x->weight = 256;
1071 else if(xx==fromx) p_x->weight = xweight;
1072 else if(xx==tox) p_x->weight = 256-w;
1073 else p_x->weight = i;
1081 for(x=0;x<newwidth;x++) {
1083 int ix2 = ((int)px)+1;
1085 if(ix2>=width) ix2=width-1;
1089 p_x[0].weight = (int)(256*(1-r));
1091 p_x[1].weight = 256-p_x[0].weight;
1097 lblockx[newwidth] = p_x;
1101 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1105 scale_lookup_t *p, **lblockx,**lblocky;
1108 if(newwidth<1 || newheight<1)
1111 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1112 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1114 lblockx = make_scale_lookup(width, newwidth);
1115 lblocky = make_scale_lookup(height, newheight);
1117 for(p=lblocky[0];p<lblocky[newheight];p++)
1120 for(y=0;y<newheight;y++) {
1121 RGBA*destline = &newdata[y*newwidth];
1123 /* create lookup table for y */
1124 rgba_int_t*l = tmpline;
1125 scale_lookup_t*p_y,*p_x;
1126 memset(tmpline, 0, width*sizeof(rgba_int_t));
1127 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1128 RGBA*line = &data[p_y->pos];
1130 int weight = p_y->weight;
1131 for(x=0;x<width;x++) {
1132 tmpline[x].r += line[x].r*weight;
1133 tmpline[x].g += line[x].g*weight;
1134 tmpline[x].b += line[x].b*weight;
1135 tmpline[x].a += line[x].a*weight;
1139 /* process x direction */
1141 for(x=0;x<newwidth;x++) {
1142 unsigned int r=0,g=0,b=0,a=0;
1143 scale_lookup_t*p_x_to = lblockx[x+1];
1145 rgba_int_t* col = &tmpline[p_x->pos];
1146 unsigned int weight = p_x->weight;
1152 } while (p_x<p_x_to);
1154 destline->r = r >> 16;
1155 destline->g = g >> 16;
1156 destline->b = b >> 16;
1157 destline->a = a >> 16;