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];
105 if(col32 == lastcol32)
107 hash = (col32 >> 17) ^ col32;
108 hash ^= ((hash>>8) + 1) ^ hash;
111 int csize = size[hash];
112 U32* cpal = &pal[hash*256];
113 for(i=0;i<csize;i++) {
119 palette_overflow = 1;
122 cpal[size[hash]++] = col32;
134 U32* cpal = &pal[t*256];
136 palette[i++] = *(RGBA*)(&cpal[s]);
147 typedef struct _JPEGDESTMGR {
148 struct jpeg_destination_mgr mgr;
151 struct jpeg_compress_struct cinfo;
152 struct jpeg_error_mgr jerr;
153 } JPEGDESTMGR, *LPJPEGDESTMGR;
155 // Destination manager callbacks
157 static void RFXSWF_init_destination(j_compress_ptr cinfo)
159 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
160 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
161 dmgr->mgr.next_output_byte = dmgr->buffer;
162 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
165 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
167 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
168 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
169 dmgr->mgr.next_output_byte = dmgr->buffer;
170 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
174 static void RFXSWF_term_destination(j_compress_ptr cinfo)
176 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
177 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
178 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
179 rfx_free(dmgr->buffer);
180 dmgr->mgr.free_in_buffer = 0;
183 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
187 // redirect compression lib output to local SWF Tag structure
189 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
191 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
193 jpeg_create_compress(&jpeg->cinfo);
195 jpeg->mgr.init_destination = RFXSWF_init_destination;
196 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
197 jpeg->mgr.term_destination = RFXSWF_term_destination;
201 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
205 jpeg->cinfo.image_width = width;
206 jpeg->cinfo.image_height = height;
207 jpeg->cinfo.input_components = 3;
208 jpeg->cinfo.in_color_space = JCS_RGB;
210 jpeg_set_defaults(&jpeg->cinfo);
211 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
213 // write tables to SWF
215 jpeg_write_tables(&jpeg->cinfo);
217 // compess image to SWF
219 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
220 jpeg_start_compress(&jpeg->cinfo, FALSE);
222 return (JPEGBITS *) jpeg;
225 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
227 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
230 jpeg_write_scanlines(&jpeg->cinfo, data, n);
234 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
236 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
239 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
241 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
244 jpeg_finish_compress(&jpeg->cinfo);
249 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
254 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
255 for (y = 0; y < height; y++) {
256 U8 scanline[3 * width];
258 for (x = 0; x < width; x++) {
259 scanline[p++] = bitmap[width * y + x].r;
260 scanline[p++] = bitmap[width * y + x].g;
261 scanline[p++] = bitmap[width * y + x].b;
263 swf_SetJPEGBitsLine(jpeg, scanline);
265 swf_SetJPEGBitsFinish(jpeg);
268 void swf_GetJPEGSize(char *fname, int *width, int *height)
270 struct jpeg_decompress_struct cinfo;
271 struct jpeg_error_mgr jerr;
275 cinfo.err = jpeg_std_error(&jerr);
276 jpeg_create_decompress(&cinfo);
277 if ((fi = fopen(fname, "rb")) == NULL) {
278 fprintf(stderr, "rfxswf: file open error\n");
281 jpeg_stdio_src(&cinfo, fi);
282 jpeg_read_header(&cinfo, TRUE);
283 *width = cinfo.image_width;
284 *height = cinfo.image_height;
285 jpeg_destroy_decompress(&cinfo);
289 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
291 struct jpeg_decompress_struct cinfo;
292 struct jpeg_error_mgr jerr;
297 cinfo.err = jpeg_std_error(&jerr);
298 jpeg_create_decompress(&cinfo);
300 if ((f = fopen(fname, "rb")) == NULL) {
301 fprintf(stderr, "rfxswf: file open error\n");
305 jpeg_stdio_src(&cinfo, f);
306 jpeg_read_header(&cinfo, TRUE);
307 jpeg_start_decompress(&cinfo);
310 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
312 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
317 if (cinfo.out_color_space == JCS_GRAYSCALE) {
318 for (y = 0; y < cinfo.output_height; y++) {
320 jpeg_read_scanlines(&cinfo, &js, 1);
321 for (x = cinfo.output_width - 1; x >= 0; x--) {
322 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
324 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
326 } else if (cinfo.out_color_space == JCS_RGB) {
327 for (y = 0; y < cinfo.output_height; y++) {
328 jpeg_read_scanlines(&cinfo, &js, 1);
329 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
331 } else if (cinfo.out_color_space == JCS_YCCK) {
333 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
335 } else if (cinfo.out_color_space == JCS_YCbCr) {
336 for (y = 0; y < cinfo.output_height; y++) {
338 for (x = 0; x < cinfo.output_width; x++) {
339 int y = js[x * 3 + 0];
340 int u = js[x * 3 + 1];
341 int v = js[x * 3 + 1];
342 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
344 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
345 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
348 } else if (cinfo.out_color_space == JCS_CMYK) {
349 for (y = 0; y < cinfo.output_height; y++) {
351 jpeg_read_scanlines(&cinfo, &js, 1);
352 /* This routine seems to work for now-
353 It's a mixture of 3 different
354 CMYK->RGB conversion routines I found in the
355 web. (which all produced garbage)
356 I'm happily accepting suggestions. (mk) */
357 for (x = 0; x < cinfo.output_width; x++) {
358 int white = 255 - js[x * 4 + 3];
359 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
360 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
361 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
363 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
368 swf_SetJPEGBitsFinish(out);
369 jpeg_finish_decompress(&cinfo);
375 /* jpeg_source_mgr functions */
376 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
378 TAG *tag = (TAG *) cinfo->client_data;
379 swf_SetTagPos(tag, 2);
380 cinfo->src->bytes_in_buffer = 0;
382 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
384 TAG *tag = (TAG *) cinfo->client_data;
385 if (tag->data[tag->pos + 0] == 0xff &&
386 tag->data[tag->pos + 1] == 0xd9 &&
387 tag->data[tag->pos + 2] == 0xff &&
388 tag->data[tag->pos + 3] == 0xd8) {
391 if (tag->pos >= tag->len) {
392 cinfo->src->next_input_byte = 0;
393 cinfo->src->bytes_in_buffer = 0;
396 cinfo->src->next_input_byte = &tag->data[tag->pos];
397 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
401 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
403 TAG *tag = (TAG *) cinfo->client_data;
404 cinfo->src->next_input_byte = 0;
405 cinfo->src->bytes_in_buffer = 0;
408 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
410 return jpeg_resync_to_restart(cinfo, desired);
412 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
414 TAG *tag = (TAG *) cinfo->client_data;
416 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
418 struct jpeg_decompress_struct cinfo;
419 struct jpeg_error_mgr jerr;
420 struct jpeg_source_mgr mgr;
426 if (tag->id == ST_DEFINEBITSJPEG) {
428 "rfxswf: extracting from definebitsjpeg not yet supported");
431 if (tag->id == ST_DEFINEBITSJPEG3) {
433 "rfxswf: extracting from definebitsjpeg3 not yet supported");
437 cinfo.err = jpeg_std_error(&jerr);
438 jpeg_create_decompress(&cinfo);
440 cinfo.client_data = (void *) tag;
442 cinfo.src->init_source = tag_init_source;
443 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
444 cinfo.src->skip_input_data = tag_skip_input_data;
445 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
446 cinfo.src->term_source = tag_term_source;
447 cinfo.out_color_space = JCS_RGB;
449 jpeg_read_header(&cinfo, TRUE);
450 *width = cinfo.image_width;
451 *height = cinfo.image_height;
453 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
455 jpeg_start_decompress(&cinfo);
456 for (y = 0; y < cinfo.output_height; y++) {
457 RGBA *line = &dest[y * cinfo.image_width];
458 U8 *to = (U8 *) line;
460 jpeg_read_scanlines(&cinfo, &to, 1);
461 for (x = cinfo.output_width - 1; x >= 0; --x) {
462 int r = to[x * 3 + 0];
463 int g = to[x * 3 + 1];
464 int b = to[x * 3 + 2];
472 jpeg_finish_decompress(&cinfo);
474 jpeg_destroy_decompress(&cinfo);
478 #endif // HAVE_JPEGLIB
480 // Lossless compression texture based on zlib
484 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
486 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
488 zs->avail_out = OUTBUFFER_SIZE;
490 int status = deflate(zs, Z_NO_FLUSH);
492 if (status != Z_OK) {
493 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
498 if (zs->next_out != data) {
499 swf_SetBlock(t, data, zs->next_out - data);
501 zs->avail_out = OUTBUFFER_SIZE;
504 if (zs->avail_in == 0)
514 int status = deflate(zs, Z_FINISH);
515 if (status != Z_OK && status != Z_STREAM_END) {
516 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
521 if (zs->next_out != data) {
522 swf_SetBlock(t, data, zs->next_out - data);
524 zs->avail_out = OUTBUFFER_SIZE;
527 if (status == Z_STREAM_END)
535 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
540 switch (bitmap_flags) {
542 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
544 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
550 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
554 swf_SetU8(t, bitmap_flags);
555 swf_SetU16(t, width);
556 swf_SetU16(t, height);
561 memset(&zs, 0x00, sizeof(z_stream));
565 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
566 zs.avail_in = bps * height;
569 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
574 res = -3; // zlib error
579 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
582 int bps = BYTES_PER_SCANLINE(width);
585 if (!pal) // create default palette for grayscale images
588 pal = rfx_alloc(256 * sizeof(RGBA));
589 for (i = 0; i < 256; i++) {
590 pal[i].r = pal[i].g = pal[i].b = i;
596 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
597 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
599 return -1; // parameter error
602 swf_SetU8(t, BMF_8BIT);
603 swf_SetU16(t, width);
604 swf_SetU16(t, height);
605 swf_SetU8(t, ncolors - 1); // number of pal entries
610 memset(&zs, 0x00, sizeof(z_stream));
614 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
615 U8 *zpal; // compress palette
616 if ((zpal = rfx_alloc(ncolors * 4))) {
620 /* be careful with ST_DEFINEBITSLOSSLESS2, because
621 the Flash player produces great bugs if you use too many
622 alpha colors in your palette. The only sensible result that
623 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
624 make transparent parts in sprites. That's the cause why alpha
625 handling is implemented in lossless routines of rfxswf.
627 Indeed: I haven't understood yet how flash player handles
628 alpha values different from 0 and 0xff in lossless bitmaps...
631 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
633 for (i = 0; i < ncolors; i++) {
640 zs.avail_in = 4 * ncolors;
642 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
649 zs.avail_in = 3 * ncolors;
654 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
659 zs.avail_in = (bps * height * sizeof(U8));
661 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
668 res = -2; // memory error
670 res = -3; // zlib error
679 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
681 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
684 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
686 int hasalpha = swf_ImageHasAlpha(data, width, height);
688 tag->id = ST_DEFINEBITSLOSSLESS;
690 tag->id = ST_DEFINEBITSLOSSLESS2;
691 /* TODO: premultiply alpha? */
693 int num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
694 if(num>1 && num<=256) {
695 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
696 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
697 int width2 = BYTES_PER_SCANLINE(width);
698 U8*data2 = (U8*)malloc(width2*height);
699 int len = width*height;
702 for(y=0;y<height;y++) {
703 RGBA*src = &data[width*y];
704 U8*dest = &data2[width2*y];
705 for(x=0;x<width;x++) {
708 if(*(U32*)&col == *(U32*)&palette[r]) {
714 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
715 col.r, col.g, col.b, col.a, num);
720 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
724 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
728 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
730 int id, format, height, width, pos;
731 U32 datalen, datalen2;
736 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
741 if (tag->id != ST_DEFINEBITSLOSSLESS &&
742 tag->id != ST_DEFINEBITSLOSSLESS2) {
743 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
747 swf_SetTagPos(tag, 0);
748 id = swf_GetU16(tag);
749 format = swf_GetU8(tag);
756 if (format != 3 && format != 5) {
759 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
762 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
766 *dwidth = width = swf_GetU16(tag);
767 *dheight = height = swf_GetU16(tag);
769 dest = rfx_alloc(sizeof(RGBA) * width * height);
772 cols = swf_GetU8(tag) + 1;
777 datalen = (width * height * bpp / 8 + cols * 8);
782 data = rfx_alloc(datalen);
784 uncompress(data, &datalen, &tag->data[tag->pos],
785 tag->len - tag->pos);
786 } while (error == Z_BUF_ERROR);
788 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
794 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
795 for (t = 0; t < cols; t++) {
796 palette[t].r = data[pos++];
797 palette[t].g = data[pos++];
798 palette[t].b = data[pos++];
800 palette[t].a = data[pos++];
805 for (y = 0; y < height; y++) {
806 int srcwidth = width * (bpp / 8);
809 // 32 bit to 24 bit "conversion"
810 for (x = 0; x < width; x++) {
811 dest[pos2].r = data[pos + 1];
812 dest[pos2].g = data[pos + 2];
813 dest[pos2].b = data[pos + 3];
816 pos += 4; //ignore padding byte
819 for (x = 0; x < width; x++) {
820 /* TODO: un-premultiply alpha? */
821 dest[pos2].r = data[pos + 1];
822 dest[pos2].g = data[pos + 2];
823 dest[pos2].b = data[pos + 3];
824 dest[pos2].a = data[pos + 0]; //alpha
830 for (x = 0; x < srcwidth; x++) {
831 dest[pos2] = palette[data[pos++]];
835 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
845 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
846 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
856 swf_SetU32(tag, 0); //placeholder
857 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
858 for (y = 0; y < height; y++) {
859 U8 scanline[3 * width];
861 for (x = 0; x < width; x++) {
862 scanline[p++] = bitmap[width * y + x].r;
863 scanline[p++] = bitmap[width * y + x].g;
864 scanline[p++] = bitmap[width * y + x].b;
866 swf_SetJPEGBitsLine(jpeg, scanline);
868 swf_SetJPEGBitsFinish(jpeg);
869 PUT32(&tag->data[pos], tag->len - pos - 4);
871 data = rfx_alloc(OUTBUFFER_SIZE);
872 memset(&zs, 0x00, sizeof(z_stream));
874 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
875 fprintf(stderr, "rfxswf: zlib compression failed");
880 zs.avail_out = OUTBUFFER_SIZE;
882 for (y = 0; y < height; y++) {
885 for (x = 0; x < width; x++) {
886 scanline[p++] = bitmap[width * y + x].a;
889 zs.next_in = scanline;
892 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
893 fprintf(stderr, "rfxswf: zlib compression failed");
896 if (zs.next_out != data) {
897 swf_SetBlock(tag, data, zs.next_out - data);
899 zs.avail_out = OUTBUFFER_SIZE;
908 int ret = deflate(&zs, Z_FINISH);
909 if (ret != Z_OK && ret != Z_STREAM_END) {
910 fprintf(stderr, "rfxswf: zlib compression failed");
913 if (zs.next_out != data) {
914 swf_SetBlock(tag, data, zs.next_out - data);
916 zs.avail_out = OUTBUFFER_SIZE;
918 if (ret == Z_STREAM_END) {
928 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
930 TAG *tag1 = 0, *tag2 = 0;
931 int has_alpha = swf_ImageHasAlpha(mem,width,height);
933 /* try lossless image */
934 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
935 swf_SetU16(tag1, bitid);
936 swf_SetLosslessImage(tag1, mem, width, height);
940 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
941 swf_SetU16(tag2, bitid);
942 swf_SetJPEGBits3(tag2, width, height, mem, quality);
944 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
945 swf_SetU16(tag2, bitid);
946 swf_SetJPEGBits2(tag2, width, height, mem, quality);
949 if(tag1 && tag1->len < tag2->len) {
950 /* use the zlib version- it's smaller */
952 if(tag) tag->next = tag1;
956 /* use the jpeg version- it's smaller */
958 if(tag) tag->next = tag2;
967 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
970 if (tag->id == ST_DEFINEBITSJPEG ||
971 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
973 return swf_JPEG2TagToImage(tag, dwidth, dheight);
975 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
979 if (tag->id == ST_DEFINEBITSLOSSLESS ||
980 tag->id == ST_DEFINEBITSLOSSLESS2) {
982 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
984 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
988 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
989 swf_TagGetName(tag));
993 #undef OUTBUFFER_SIZE
996 void swf_RemoveJPEGTables(SWF * swf)
998 TAG *tag = swf->firstTag;
1001 if (tag->id == ST_JPEGTABLES) {
1010 tag = swf->firstTag;
1012 if (tag->id == ST_DEFINEBITSJPEG) {
1013 void *data = rfx_alloc(tag->len);
1014 swf_GetBlock(tag, data, tag->len);
1015 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1016 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1017 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1018 swf_SetBlock(tag, &((U8*)data)[2], tag->len-2);
1023 if (swf->firstTag == tables_tag)
1024 swf->firstTag = tables_tag->next;
1025 swf_DeleteTag(tables_tag);
1028 typedef struct scale_lookup {
1030 unsigned int weight;
1033 typedef struct rgba_int {
1034 unsigned int r,g,b,a;
1037 static int bicubic = 0;
1039 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1041 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1042 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1043 double fx = ((double)width)/((double)newwidth);
1046 scale_lookup_t*p_x = lookupx;
1048 if(newwidth<=width) {
1049 for(x=0;x<newwidth;x++) {
1051 double ex = px + fx;
1052 int fromx = (int)px;
1054 double rem = fromx+1-px;
1055 int i = (int)(256/fx);
1056 int xweight = (int)(rem*256/fx);
1059 if(tox>=width) tox = width-1;
1060 for(xx=fromx;xx<=tox;xx++) {
1061 if(xx==fromx && xx==tox) p_x->weight = 256;
1062 else if(xx==fromx) p_x->weight = xweight;
1063 else if(xx==tox) p_x->weight = 256-w;
1064 else p_x->weight = i;
1072 for(x=0;x<newwidth;x++) {
1075 int ix2 = ((int)px)+1;
1076 if(ix2>=width) ix2=width-1;
1080 p_x[0].weight = (int)(256*(1-r));
1082 p_x[1].weight = 256-p_x[0].weight;
1088 lblockx[newwidth] = p_x;
1092 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1094 if(newwidth<1 || newheight<1)
1097 RGBA* newdata= (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1098 scale_lookup_t *p, **lblockx,**lblocky;
1099 rgba_int_t*tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1101 lblockx = make_scale_lookup(width, newwidth);
1102 lblocky = make_scale_lookup(height, newheight);
1104 for(p=lblocky[0];p<lblocky[newheight];p++)
1107 for(y=0;y<newheight;y++) {
1108 RGBA*destline = &newdata[y*newwidth];
1110 /* create lookup table for y */
1111 rgba_int_t*l = tmpline;
1113 memset(tmpline, 0, width*sizeof(rgba_int_t));
1114 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1115 RGBA*line = &data[p_y->pos];
1117 int weight = p_y->weight;
1118 for(x=0;x<width;x++) {
1119 tmpline[x].r += line[x].r*weight;
1120 tmpline[x].g += line[x].g*weight;
1121 tmpline[x].b += line[x].b*weight;
1122 tmpline[x].a += line[x].a*weight;
1126 /* process x direction */
1127 scale_lookup_t*p_x = lblockx[0];
1128 for(x=0;x<newwidth;x++) {
1129 unsigned int r=0,g=0,b=0,a=0;
1130 scale_lookup_t*p_x_to = lblockx[x+1];
1132 rgba_int_t* col = &tmpline[p_x->pos];
1133 unsigned int weight = p_x->weight;
1139 } while (p_x<p_x_to);
1141 destline->r = r >> 16;
1142 destline->g = g >> 16;
1143 destline->b = b >> 16;
1144 destline->a = a >> 16;