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;
153 if(palette_overflow) {
162 U32* cpal = &pal[t*256];
164 palette[i++] = *(RGBA*)(&cpal[s]);
175 typedef struct _JPEGDESTMGR {
176 struct jpeg_destination_mgr mgr;
179 struct jpeg_compress_struct cinfo;
180 struct jpeg_error_mgr jerr;
181 } JPEGDESTMGR, *LPJPEGDESTMGR;
183 // Destination manager callbacks
185 static void RFXSWF_init_destination(j_compress_ptr cinfo)
187 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
188 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
189 dmgr->mgr.next_output_byte = dmgr->buffer;
190 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
193 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
195 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
196 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
197 dmgr->mgr.next_output_byte = dmgr->buffer;
198 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
202 static void RFXSWF_term_destination(j_compress_ptr cinfo)
204 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
205 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
206 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
207 rfx_free(dmgr->buffer);
208 dmgr->mgr.free_in_buffer = 0;
211 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
215 // redirect compression lib output to local SWF Tag structure
217 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
219 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
221 jpeg_create_compress(&jpeg->cinfo);
223 jpeg->mgr.init_destination = RFXSWF_init_destination;
224 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
225 jpeg->mgr.term_destination = RFXSWF_term_destination;
229 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
233 jpeg->cinfo.image_width = width;
234 jpeg->cinfo.image_height = height;
235 jpeg->cinfo.input_components = 3;
236 jpeg->cinfo.in_color_space = JCS_RGB;
238 jpeg_set_defaults(&jpeg->cinfo);
239 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
241 // write tables to SWF
243 jpeg_write_tables(&jpeg->cinfo);
245 // compess image to SWF
247 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
248 jpeg_start_compress(&jpeg->cinfo, FALSE);
250 return (JPEGBITS *) jpeg;
253 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
255 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
258 jpeg_write_scanlines(&jpeg->cinfo, data, n);
262 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
264 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
267 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
269 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
272 jpeg_finish_compress(&jpeg->cinfo);
277 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
282 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
283 for (y = 0; y < height; y++) {
284 U8 scanline[3 * width];
286 for (x = 0; x < width; x++) {
287 scanline[p++] = bitmap[width * y + x].r;
288 scanline[p++] = bitmap[width * y + x].g;
289 scanline[p++] = bitmap[width * y + x].b;
291 swf_SetJPEGBitsLine(jpeg, scanline);
293 swf_SetJPEGBitsFinish(jpeg);
296 void swf_GetJPEGSize(char *fname, int *width, int *height)
298 struct jpeg_decompress_struct cinfo;
299 struct jpeg_error_mgr jerr;
303 cinfo.err = jpeg_std_error(&jerr);
304 jpeg_create_decompress(&cinfo);
305 if ((fi = fopen(fname, "rb")) == NULL) {
306 fprintf(stderr, "rfxswf: file open error\n");
309 jpeg_stdio_src(&cinfo, fi);
310 jpeg_read_header(&cinfo, TRUE);
311 *width = cinfo.image_width;
312 *height = cinfo.image_height;
313 jpeg_destroy_decompress(&cinfo);
317 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
319 struct jpeg_decompress_struct cinfo;
320 struct jpeg_error_mgr jerr;
325 cinfo.err = jpeg_std_error(&jerr);
326 jpeg_create_decompress(&cinfo);
328 if ((f = fopen(fname, "rb")) == NULL) {
329 fprintf(stderr, "rfxswf: file open error\n");
333 jpeg_stdio_src(&cinfo, f);
334 jpeg_read_header(&cinfo, TRUE);
335 jpeg_start_decompress(&cinfo);
338 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
340 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
345 if (cinfo.out_color_space == JCS_GRAYSCALE) {
346 for (y = 0; y < cinfo.output_height; y++) {
348 jpeg_read_scanlines(&cinfo, &js, 1);
349 for (x = cinfo.output_width - 1; x >= 0; x--) {
350 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
352 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
354 } else if (cinfo.out_color_space == JCS_RGB) {
355 for (y = 0; y < cinfo.output_height; y++) {
356 jpeg_read_scanlines(&cinfo, &js, 1);
357 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
359 } else if (cinfo.out_color_space == JCS_YCCK) {
361 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
363 } else if (cinfo.out_color_space == JCS_YCbCr) {
364 for (y = 0; y < cinfo.output_height; y++) {
366 for (x = 0; x < cinfo.output_width; x++) {
367 int y = js[x * 3 + 0];
368 int u = js[x * 3 + 1];
369 int v = js[x * 3 + 1];
370 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
372 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
373 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
376 } else if (cinfo.out_color_space == JCS_CMYK) {
377 for (y = 0; y < cinfo.output_height; y++) {
379 jpeg_read_scanlines(&cinfo, &js, 1);
380 /* This routine seems to work for now-
381 It's a mixture of 3 different
382 CMYK->RGB conversion routines I found in the
383 web. (which all produced garbage)
384 I'm happily accepting suggestions. (mk) */
385 for (x = 0; x < cinfo.output_width; x++) {
386 int white = 255 - js[x * 4 + 3];
387 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
388 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
389 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
391 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
396 swf_SetJPEGBitsFinish(out);
397 jpeg_finish_decompress(&cinfo);
403 /* jpeg_source_mgr functions */
404 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
406 TAG *tag = (TAG *) cinfo->client_data;
407 if (tag->id == ST_DEFINEBITSJPEG3) {
408 swf_SetTagPos(tag, 6);
410 swf_SetTagPos(tag, 2);
412 cinfo->src->bytes_in_buffer = 0;
414 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
416 TAG *tag = (TAG *) cinfo->client_data;
417 if (tag->data[tag->pos + 0] == 0xff &&
418 tag->data[tag->pos + 1] == 0xd9 &&
419 tag->data[tag->pos + 2] == 0xff &&
420 tag->data[tag->pos + 3] == 0xd8) {
423 if (tag->pos >= tag->len) {
424 cinfo->src->next_input_byte = 0;
425 cinfo->src->bytes_in_buffer = 0;
428 cinfo->src->next_input_byte = &tag->data[tag->pos];
429 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
433 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
435 TAG *tag = (TAG *) cinfo->client_data;
436 cinfo->src->next_input_byte = 0;
437 cinfo->src->bytes_in_buffer = 0;
440 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
442 return jpeg_resync_to_restart(cinfo, desired);
444 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
446 TAG *tag = (TAG *) cinfo->client_data;
448 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
450 struct jpeg_decompress_struct cinfo;
451 struct jpeg_error_mgr jerr;
452 struct jpeg_source_mgr mgr;
460 if (tag->id == ST_DEFINEBITSJPEG) {
461 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
464 if (tag->id == ST_DEFINEBITSJPEG3) {
466 offset = swf_GetU32(tag);
467 oldtaglen = tag->len;
470 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
475 cinfo.err = jpeg_std_error(&jerr);
476 jpeg_create_decompress(&cinfo);
478 cinfo.client_data = (void *) tag;
480 cinfo.src->init_source = tag_init_source;
481 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
482 cinfo.src->skip_input_data = tag_skip_input_data;
483 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
484 cinfo.src->term_source = tag_term_source;
485 cinfo.out_color_space = JCS_RGB;
487 jpeg_read_header(&cinfo, TRUE);
488 *width = cinfo.image_width;
489 *height = cinfo.image_height;
491 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
493 jpeg_start_decompress(&cinfo);
494 for (y = 0; y < cinfo.output_height; y++) {
495 RGBA *line = &dest[y * cinfo.image_width];
496 U8 *to = (U8 *) line;
498 jpeg_read_scanlines(&cinfo, &to, 1);
499 for (x = cinfo.output_width - 1; x >= 0; --x) {
500 int r = to[x * 3 + 0];
501 int g = to[x * 3 + 1];
502 int b = to[x * 3 + 2];
510 jpeg_finish_decompress(&cinfo);
512 jpeg_destroy_decompress(&cinfo);
516 U32 datalen = cinfo.output_width*cinfo.output_height;
517 U8* alphadata = (U8*)rfx_alloc(datalen);
519 tag->len = oldtaglen;
520 swf_SetTagPos(tag, 6+offset);
521 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
523 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
526 for(y=0;y<cinfo.output_height;y++) {
527 RGBA*line = &dest[y*cinfo.output_width];
528 U8*aline = &alphadata[y*cinfo.output_width];
530 for(x=0;x<cinfo.output_width;x++) {
531 line[x].a = aline[x];
540 #endif // HAVE_JPEGLIB
542 // Lossless compression texture based on zlib
546 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
548 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
550 zs->avail_out = OUTBUFFER_SIZE;
552 int status = deflate(zs, Z_NO_FLUSH);
554 if (status != Z_OK) {
555 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
560 if (zs->next_out != data) {
561 swf_SetBlock(t, data, zs->next_out - data);
563 zs->avail_out = OUTBUFFER_SIZE;
566 if (zs->avail_in == 0)
576 int status = deflate(zs, Z_FINISH);
577 if (status != Z_OK && status != Z_STREAM_END) {
578 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
583 if (zs->next_out != data) {
584 swf_SetBlock(t, data, zs->next_out - data);
586 zs->avail_out = OUTBUFFER_SIZE;
589 if (status == Z_STREAM_END)
597 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
602 switch (bitmap_flags) {
604 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
606 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
612 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
616 swf_SetU8(t, bitmap_flags);
617 swf_SetU16(t, width);
618 swf_SetU16(t, height);
623 memset(&zs, 0x00, sizeof(z_stream));
627 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
628 zs.avail_in = bps * height;
631 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
636 res = -3; // zlib error
641 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
644 int bps = BYTES_PER_SCANLINE(width);
647 if (!pal) // create default palette for grayscale images
650 pal = rfx_alloc(256 * sizeof(RGBA));
651 for (i = 0; i < 256; i++) {
652 pal[i].r = pal[i].g = pal[i].b = i;
658 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
659 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
661 return -1; // parameter error
664 swf_SetU8(t, BMF_8BIT);
665 swf_SetU16(t, width);
666 swf_SetU16(t, height);
667 swf_SetU8(t, ncolors - 1); // number of pal entries
672 memset(&zs, 0x00, sizeof(z_stream));
676 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
677 U8 *zpal; // compress palette
678 if ((zpal = rfx_alloc(ncolors * 4))) {
682 /* be careful with ST_DEFINEBITSLOSSLESS2, because
683 the Flash player produces great bugs if you use too many
684 alpha colors in your palette. The only sensible result that
685 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
686 make transparent parts in sprites. That's the cause why alpha
687 handling is implemented in lossless routines of rfxswf.
689 Indeed: I haven't understood yet how flash player handles
690 alpha values different from 0 and 0xff in lossless bitmaps...
693 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
695 for (i = 0; i < ncolors; i++) {
702 zs.avail_in = 4 * ncolors;
704 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
711 zs.avail_in = 3 * ncolors;
716 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
721 zs.avail_in = (bps * height * sizeof(U8));
723 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
730 res = -2; // memory error
732 res = -3; // zlib error
741 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
743 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
746 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
748 int num = width*height;
751 data[t].r = ((int)data[t].r*data[t].a)/255;
752 data[t].g = ((int)data[t].g*data[t].a)/255;
753 data[t].b = ((int)data[t].b*data[t].a)/255;
757 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
759 int hasalpha = swf_ImageHasAlpha(data, width, height);
762 tag->id = ST_DEFINEBITSLOSSLESS;
764 tag->id = ST_DEFINEBITSLOSSLESS2;
765 swf_PreMultiplyAlpha(data, width, height);
767 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
768 if(num>1 && num<=256) {
769 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
770 int width2 = BYTES_PER_SCANLINE(width);
771 U8*data2 = (U8*)malloc(width2*height);
772 int len = width*height;
775 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
776 for(y=0;y<height;y++) {
777 RGBA*src = &data[width*y];
778 U8*dest = &data2[width2*y];
779 for(x=0;x<width;x++) {
782 if(*(U32*)&col == *(U32*)&palette[r]) {
788 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
789 col.r, col.g, col.b, col.a, num);
794 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
798 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
802 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
804 int id, format, height, width, pos;
805 U32 datalen, datalen2;
810 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
815 if (tag->id != ST_DEFINEBITSLOSSLESS &&
816 tag->id != ST_DEFINEBITSLOSSLESS2) {
817 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
821 swf_SetTagPos(tag, 0);
822 id = swf_GetU16(tag);
823 format = swf_GetU8(tag);
830 if (format != 3 && format != 5) {
833 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
836 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
840 *dwidth = width = swf_GetU16(tag);
841 *dheight = height = swf_GetU16(tag);
843 dest = rfx_alloc(sizeof(RGBA) * width * height);
846 cols = swf_GetU8(tag) + 1;
851 datalen = (width * height * bpp / 8 + cols * 8);
856 data = rfx_alloc(datalen);
858 uncompress(data, &datalen, &tag->data[tag->pos],
859 tag->len - tag->pos);
860 } while (error == Z_BUF_ERROR);
862 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
868 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
869 for (t = 0; t < cols; t++) {
870 palette[t].r = data[pos++];
871 palette[t].g = data[pos++];
872 palette[t].b = data[pos++];
874 palette[t].a = data[pos++];
881 for (y = 0; y < height; y++) {
882 int srcwidth = width * (bpp / 8);
885 // 32 bit to 24 bit "conversion"
886 for (x = 0; x < width; x++) {
887 dest[pos2].r = data[pos + 1];
888 dest[pos2].g = data[pos + 2];
889 dest[pos2].b = data[pos + 3];
892 pos += 4; //ignore padding byte
895 for (x = 0; x < width; x++) {
896 /* TODO: is un-premultiplying alpha the right thing to do?
897 dest[pos2].r = data[pos + 1];
898 dest[pos2].g = data[pos + 2];
899 dest[pos2].b = data[pos + 3];*/
900 int alpha = data[pos+0];
902 dest[pos2].r = ((int)data[pos + 1]*255)/alpha;
903 dest[pos2].g = ((int)data[pos + 2]*255)/alpha;
904 dest[pos2].b = ((int)data[pos + 3]*255)/alpha;
906 dest[pos2].r = data[pos + 1];
907 dest[pos2].g = data[pos + 2];
908 dest[pos2].b = data[pos + 3];
910 dest[pos2].a = data[pos + 0]; //alpha
916 for (x = 0; x < srcwidth; x++) {
917 dest[pos2] = palette[data[pos++]];
921 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
931 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
932 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
942 swf_SetU32(tag, 0); //placeholder
943 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
944 for (y = 0; y < height; y++) {
945 U8 scanline[3 * width];
947 for (x = 0; x < width; x++) {
948 scanline[p++] = bitmap[width * y + x].r;
949 scanline[p++] = bitmap[width * y + x].g;
950 scanline[p++] = bitmap[width * y + x].b;
952 swf_SetJPEGBitsLine(jpeg, scanline);
954 swf_SetJPEGBitsFinish(jpeg);
955 PUT32(&tag->data[pos], tag->len - pos - 4);
957 data = rfx_alloc(OUTBUFFER_SIZE);
958 memset(&zs, 0x00, sizeof(z_stream));
960 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
961 fprintf(stderr, "rfxswf: zlib compression failed");
966 zs.avail_out = OUTBUFFER_SIZE;
968 for (y = 0; y < height; y++) {
971 for (x = 0; x < width; x++) {
972 scanline[p++] = bitmap[width * y + x].a;
975 zs.next_in = scanline;
978 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
979 fprintf(stderr, "rfxswf: zlib compression failed");
982 if (zs.next_out != data) {
983 swf_SetBlock(tag, data, zs.next_out - data);
985 zs.avail_out = OUTBUFFER_SIZE;
994 int ret = deflate(&zs, Z_FINISH);
995 if (ret != Z_OK && ret != Z_STREAM_END) {
996 fprintf(stderr, "rfxswf: zlib compression failed");
999 if (zs.next_out != data) {
1000 swf_SetBlock(tag, data, zs.next_out - data);
1002 zs.avail_out = OUTBUFFER_SIZE;
1004 if (ret == Z_STREAM_END) {
1014 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1016 TAG *tag1 = 0, *tag2 = 0;
1017 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1019 /* try lossless image */
1020 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1021 swf_SetU16(tag1, bitid);
1022 swf_SetLosslessImage(tag1, mem, width, height);
1024 /* try jpeg image */
1026 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1027 swf_SetU16(tag2, bitid);
1028 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1030 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1031 swf_SetU16(tag2, bitid);
1032 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1035 if(tag1 && tag1->len < tag2->len) {
1036 /* use the zlib version- it's smaller */
1038 if(tag) tag->next = tag1;
1040 swf_DeleteTag(tag2);
1042 /* use the jpeg version- it's smaller */
1044 if(tag) tag->next = tag2;
1046 swf_DeleteTag(tag1);
1053 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1057 swf_SetTagPos(tag, 2); // id is 2 bytes
1059 if (tag->id == ST_DEFINEBITSJPEG ||
1060 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1062 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1064 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1068 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1069 tag->id == ST_DEFINEBITSLOSSLESS2) {
1071 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1073 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1077 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1078 swf_TagGetName(tag));
1082 #undef OUTBUFFER_SIZE
1085 void swf_RemoveJPEGTables(SWF * swf)
1087 TAG *tag = swf->firstTag;
1088 TAG *tables_tag = 0;
1090 if (tag->id == ST_JPEGTABLES) {
1099 tag = swf->firstTag;
1101 if (tag->id == ST_DEFINEBITSJPEG) {
1103 void *data = rfx_alloc(len);
1104 swf_GetBlock(tag, data, tag->len);
1105 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1106 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1107 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1108 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1113 if (swf->firstTag == tables_tag)
1114 swf->firstTag = tables_tag->next;
1115 swf_DeleteTag(tables_tag);
1118 typedef struct scale_lookup {
1120 unsigned int weight;
1123 typedef struct rgba_int {
1124 unsigned int r,g,b,a;
1127 static int bicubic = 0;
1129 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1131 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1132 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1133 double fx = ((double)width)/((double)newwidth);
1136 scale_lookup_t*p_x = lookupx;
1138 if(newwidth<=width) {
1139 for(x=0;x<newwidth;x++) {
1140 double ex = px + fx;
1141 int fromx = (int)px;
1143 double rem = fromx+1-px;
1144 int i = (int)(256/fx);
1145 int xweight = (int)(rem*256/fx);
1149 if(tox>=width) tox = width-1;
1150 for(xx=fromx;xx<=tox;xx++) {
1151 if(xx==fromx && xx==tox) p_x->weight = 256;
1152 else if(xx==fromx) p_x->weight = xweight;
1153 else if(xx==tox) p_x->weight = 256-w;
1154 else p_x->weight = i;
1162 for(x=0;x<newwidth;x++) {
1164 int ix2 = ((int)px)+1;
1166 if(ix2>=width) ix2=width-1;
1170 p_x[0].weight = (int)(256*(1-r));
1172 p_x[1].weight = 256-p_x[0].weight;
1178 lblockx[newwidth] = p_x;
1181 static int monochrome_warning = 0;
1182 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1186 scale_lookup_t *p, **lblockx,**lblocky;
1189 if(newwidth<1 || newheight<1)
1192 /* this is bad because this scaler doesn't yet handle monochrome
1193 images with 2 colors in a way that the final image hasn't more
1195 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1196 if(!monochrome_warning) {
1197 fprintf(stderr, "Warning: scaling monochrome image\n");
1198 monochrome_warning = 1;
1202 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1203 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1205 lblockx = make_scale_lookup(width, newwidth);
1206 lblocky = make_scale_lookup(height, newheight);
1208 for(p=lblocky[0];p<lblocky[newheight];p++)
1211 for(y=0;y<newheight;y++) {
1212 RGBA*destline = &newdata[y*newwidth];
1214 /* create lookup table for y */
1215 rgba_int_t*l = tmpline;
1216 scale_lookup_t*p_y,*p_x;
1217 memset(tmpline, 0, width*sizeof(rgba_int_t));
1218 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1219 RGBA*line = &data[p_y->pos];
1221 int weight = p_y->weight;
1222 for(x=0;x<width;x++) {
1223 tmpline[x].r += line[x].r*weight;
1224 tmpline[x].g += line[x].g*weight;
1225 tmpline[x].b += line[x].b*weight;
1226 tmpline[x].a += line[x].a*weight;
1230 /* process x direction */
1232 for(x=0;x<newwidth;x++) {
1233 unsigned int r=0,g=0,b=0,a=0;
1234 scale_lookup_t*p_x_to = lblockx[x+1];
1236 rgba_int_t* col = &tmpline[p_x->pos];
1237 unsigned int weight = p_x->weight;
1243 } while (p_x<p_x_to);
1245 destline->r = r >> 16;
1246 destline->g = g >> 16;
1247 destline->b = b >> 16;
1248 destline->a = a >> 16;