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;
160 U32* cpal = &pal[t*256];
162 palette[i++] = *(RGBA*)(&cpal[s]);
173 typedef struct _JPEGDESTMGR {
174 struct jpeg_destination_mgr mgr;
177 struct jpeg_compress_struct cinfo;
178 struct jpeg_error_mgr jerr;
179 } JPEGDESTMGR, *LPJPEGDESTMGR;
181 // Destination manager callbacks
183 static void RFXSWF_init_destination(j_compress_ptr cinfo)
185 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
186 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
187 dmgr->mgr.next_output_byte = dmgr->buffer;
188 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
191 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
193 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
194 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
195 dmgr->mgr.next_output_byte = dmgr->buffer;
196 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
200 static void RFXSWF_term_destination(j_compress_ptr cinfo)
202 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
203 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
204 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
205 rfx_free(dmgr->buffer);
206 dmgr->mgr.free_in_buffer = 0;
209 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
213 // redirect compression lib output to local SWF Tag structure
215 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
217 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
219 jpeg_create_compress(&jpeg->cinfo);
221 jpeg->mgr.init_destination = RFXSWF_init_destination;
222 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
223 jpeg->mgr.term_destination = RFXSWF_term_destination;
227 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
231 jpeg->cinfo.image_width = width;
232 jpeg->cinfo.image_height = height;
233 jpeg->cinfo.input_components = 3;
234 jpeg->cinfo.in_color_space = JCS_RGB;
236 jpeg_set_defaults(&jpeg->cinfo);
237 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
239 // write tables to SWF
241 jpeg_write_tables(&jpeg->cinfo);
243 // compess image to SWF
245 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
246 jpeg_start_compress(&jpeg->cinfo, FALSE);
248 return (JPEGBITS *) jpeg;
251 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
253 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
256 jpeg_write_scanlines(&jpeg->cinfo, data, n);
260 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
262 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
265 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
267 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
270 jpeg_finish_compress(&jpeg->cinfo);
275 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
280 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
281 for (y = 0; y < height; y++) {
282 U8 scanline[3 * width];
284 for (x = 0; x < width; x++) {
285 scanline[p++] = bitmap[width * y + x].r;
286 scanline[p++] = bitmap[width * y + x].g;
287 scanline[p++] = bitmap[width * y + x].b;
289 swf_SetJPEGBitsLine(jpeg, scanline);
291 swf_SetJPEGBitsFinish(jpeg);
294 void swf_GetJPEGSize(char *fname, int *width, int *height)
296 struct jpeg_decompress_struct cinfo;
297 struct jpeg_error_mgr jerr;
301 cinfo.err = jpeg_std_error(&jerr);
302 jpeg_create_decompress(&cinfo);
303 if ((fi = fopen(fname, "rb")) == NULL) {
304 fprintf(stderr, "rfxswf: file open error\n");
307 jpeg_stdio_src(&cinfo, fi);
308 jpeg_read_header(&cinfo, TRUE);
309 *width = cinfo.image_width;
310 *height = cinfo.image_height;
311 jpeg_destroy_decompress(&cinfo);
315 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
317 struct jpeg_decompress_struct cinfo;
318 struct jpeg_error_mgr jerr;
323 cinfo.err = jpeg_std_error(&jerr);
324 jpeg_create_decompress(&cinfo);
326 if ((f = fopen(fname, "rb")) == NULL) {
327 fprintf(stderr, "rfxswf: file open error\n");
331 jpeg_stdio_src(&cinfo, f);
332 jpeg_read_header(&cinfo, TRUE);
333 jpeg_start_decompress(&cinfo);
336 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
338 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
343 if (cinfo.out_color_space == JCS_GRAYSCALE) {
344 for (y = 0; y < cinfo.output_height; y++) {
346 jpeg_read_scanlines(&cinfo, &js, 1);
347 for (x = cinfo.output_width - 1; x >= 0; x--) {
348 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
350 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
352 } else if (cinfo.out_color_space == JCS_RGB) {
353 for (y = 0; y < cinfo.output_height; y++) {
354 jpeg_read_scanlines(&cinfo, &js, 1);
355 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
357 } else if (cinfo.out_color_space == JCS_YCCK) {
359 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
361 } else if (cinfo.out_color_space == JCS_YCbCr) {
362 for (y = 0; y < cinfo.output_height; y++) {
364 for (x = 0; x < cinfo.output_width; x++) {
365 int y = js[x * 3 + 0];
366 int u = js[x * 3 + 1];
367 int v = js[x * 3 + 1];
368 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
370 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
371 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
374 } else if (cinfo.out_color_space == JCS_CMYK) {
375 for (y = 0; y < cinfo.output_height; y++) {
377 jpeg_read_scanlines(&cinfo, &js, 1);
378 /* This routine seems to work for now-
379 It's a mixture of 3 different
380 CMYK->RGB conversion routines I found in the
381 web. (which all produced garbage)
382 I'm happily accepting suggestions. (mk) */
383 for (x = 0; x < cinfo.output_width; x++) {
384 int white = 255 - js[x * 4 + 3];
385 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
386 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
387 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
389 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
394 swf_SetJPEGBitsFinish(out);
395 jpeg_finish_decompress(&cinfo);
401 /* jpeg_source_mgr functions */
402 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
404 TAG *tag = (TAG *) cinfo->client_data;
405 if (tag->id == ST_DEFINEBITSJPEG3) {
406 swf_SetTagPos(tag, 6);
408 swf_SetTagPos(tag, 2);
410 cinfo->src->bytes_in_buffer = 0;
412 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
414 TAG *tag = (TAG *) cinfo->client_data;
415 if (tag->data[tag->pos + 0] == 0xff &&
416 tag->data[tag->pos + 1] == 0xd9 &&
417 tag->data[tag->pos + 2] == 0xff &&
418 tag->data[tag->pos + 3] == 0xd8) {
421 if (tag->pos >= tag->len) {
422 cinfo->src->next_input_byte = 0;
423 cinfo->src->bytes_in_buffer = 0;
426 cinfo->src->next_input_byte = &tag->data[tag->pos];
427 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
431 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
433 TAG *tag = (TAG *) cinfo->client_data;
434 cinfo->src->next_input_byte = 0;
435 cinfo->src->bytes_in_buffer = 0;
438 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
440 return jpeg_resync_to_restart(cinfo, desired);
442 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
444 TAG *tag = (TAG *) cinfo->client_data;
446 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
448 struct jpeg_decompress_struct cinfo;
449 struct jpeg_error_mgr jerr;
450 struct jpeg_source_mgr mgr;
458 if (tag->id == ST_DEFINEBITSJPEG) {
459 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
462 if (tag->id == ST_DEFINEBITSJPEG3) {
464 offset = swf_GetU32(tag);
465 oldtaglen = tag->len;
468 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
473 cinfo.err = jpeg_std_error(&jerr);
474 jpeg_create_decompress(&cinfo);
476 cinfo.client_data = (void *) tag;
478 cinfo.src->init_source = tag_init_source;
479 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
480 cinfo.src->skip_input_data = tag_skip_input_data;
481 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
482 cinfo.src->term_source = tag_term_source;
483 cinfo.out_color_space = JCS_RGB;
485 jpeg_read_header(&cinfo, TRUE);
486 *width = cinfo.image_width;
487 *height = cinfo.image_height;
489 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
491 jpeg_start_decompress(&cinfo);
492 for (y = 0; y < cinfo.output_height; y++) {
493 RGBA *line = &dest[y * cinfo.image_width];
494 U8 *to = (U8 *) line;
496 jpeg_read_scanlines(&cinfo, &to, 1);
497 for (x = cinfo.output_width - 1; x >= 0; --x) {
498 int r = to[x * 3 + 0];
499 int g = to[x * 3 + 1];
500 int b = to[x * 3 + 2];
508 jpeg_finish_decompress(&cinfo);
510 jpeg_destroy_decompress(&cinfo);
514 U32 datalen = cinfo.output_width*cinfo.output_height;
515 U8* alphadata = (U8*)rfx_alloc(datalen);
517 tag->len = oldtaglen;
518 swf_SetTagPos(tag, 6+offset);
519 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
521 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
524 for(y=0;y<cinfo.output_height;y++) {
525 RGBA*line = &dest[y*cinfo.output_width];
526 U8*aline = &alphadata[y*cinfo.output_width];
528 for(x=0;x<cinfo.output_width;x++) {
529 line[x].a = aline[x];
538 #endif // HAVE_JPEGLIB
540 // Lossless compression texture based on zlib
544 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
546 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
548 zs->avail_out = OUTBUFFER_SIZE;
550 int status = deflate(zs, Z_NO_FLUSH);
552 if (status != Z_OK) {
553 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
558 if (zs->next_out != data) {
559 swf_SetBlock(t, data, zs->next_out - data);
561 zs->avail_out = OUTBUFFER_SIZE;
564 if (zs->avail_in == 0)
574 int status = deflate(zs, Z_FINISH);
575 if (status != Z_OK && status != Z_STREAM_END) {
576 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
581 if (zs->next_out != data) {
582 swf_SetBlock(t, data, zs->next_out - data);
584 zs->avail_out = OUTBUFFER_SIZE;
587 if (status == Z_STREAM_END)
595 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
600 switch (bitmap_flags) {
602 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
604 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
610 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
614 swf_SetU8(t, bitmap_flags);
615 swf_SetU16(t, width);
616 swf_SetU16(t, height);
621 memset(&zs, 0x00, sizeof(z_stream));
625 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
626 zs.avail_in = bps * height;
629 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
634 res = -3; // zlib error
639 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
642 int bps = BYTES_PER_SCANLINE(width);
645 if (!pal) // create default palette for grayscale images
648 pal = rfx_alloc(256 * sizeof(RGBA));
649 for (i = 0; i < 256; i++) {
650 pal[i].r = pal[i].g = pal[i].b = i;
656 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
657 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
659 return -1; // parameter error
662 swf_SetU8(t, BMF_8BIT);
663 swf_SetU16(t, width);
664 swf_SetU16(t, height);
665 swf_SetU8(t, ncolors - 1); // number of pal entries
670 memset(&zs, 0x00, sizeof(z_stream));
674 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
675 U8 *zpal; // compress palette
676 if ((zpal = rfx_alloc(ncolors * 4))) {
680 /* be careful with ST_DEFINEBITSLOSSLESS2, because
681 the Flash player produces great bugs if you use too many
682 alpha colors in your palette. The only sensible result that
683 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
684 make transparent parts in sprites. That's the cause why alpha
685 handling is implemented in lossless routines of rfxswf.
687 Indeed: I haven't understood yet how flash player handles
688 alpha values different from 0 and 0xff in lossless bitmaps...
691 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
693 for (i = 0; i < ncolors; i++) {
700 zs.avail_in = 4 * ncolors;
702 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
709 zs.avail_in = 3 * ncolors;
714 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
719 zs.avail_in = (bps * height * sizeof(U8));
721 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
728 res = -2; // memory error
730 res = -3; // zlib error
739 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
741 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
744 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
746 int num = width*height;
749 data[t].r = ((int)data[t].r*data[t].a)/255;
750 data[t].g = ((int)data[t].g*data[t].a)/255;
751 data[t].b = ((int)data[t].b*data[t].a)/255;
755 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
757 int hasalpha = swf_ImageHasAlpha(data, width, height);
760 tag->id = ST_DEFINEBITSLOSSLESS;
762 tag->id = ST_DEFINEBITSLOSSLESS2;
763 swf_PreMultiplyAlpha(data, width, height);
765 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
766 if(num>1 && num<=256) {
767 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
768 int width2 = BYTES_PER_SCANLINE(width);
769 U8*data2 = (U8*)malloc(width2*height);
770 int len = width*height;
773 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
774 for(y=0;y<height;y++) {
775 RGBA*src = &data[width*y];
776 U8*dest = &data2[width2*y];
777 for(x=0;x<width;x++) {
780 if(*(U32*)&col == *(U32*)&palette[r]) {
786 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
787 col.r, col.g, col.b, col.a, num);
792 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
796 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
800 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
802 int id, format, height, width, pos;
803 U32 datalen, datalen2;
808 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
813 if (tag->id != ST_DEFINEBITSLOSSLESS &&
814 tag->id != ST_DEFINEBITSLOSSLESS2) {
815 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
819 swf_SetTagPos(tag, 0);
820 id = swf_GetU16(tag);
821 format = swf_GetU8(tag);
828 if (format != 3 && format != 5) {
831 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
834 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
838 *dwidth = width = swf_GetU16(tag);
839 *dheight = height = swf_GetU16(tag);
841 dest = rfx_alloc(sizeof(RGBA) * width * height);
844 cols = swf_GetU8(tag) + 1;
849 datalen = (width * height * bpp / 8 + cols * 8);
854 data = rfx_alloc(datalen);
856 uncompress(data, &datalen, &tag->data[tag->pos],
857 tag->len - tag->pos);
858 } while (error == Z_BUF_ERROR);
860 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
866 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
867 for (t = 0; t < cols; t++) {
868 palette[t].r = data[pos++];
869 palette[t].g = data[pos++];
870 palette[t].b = data[pos++];
872 palette[t].a = data[pos++];
879 for (y = 0; y < height; y++) {
880 int srcwidth = width * (bpp / 8);
883 // 32 bit to 24 bit "conversion"
884 for (x = 0; x < width; x++) {
885 dest[pos2].r = data[pos + 1];
886 dest[pos2].g = data[pos + 2];
887 dest[pos2].b = data[pos + 3];
890 pos += 4; //ignore padding byte
893 for (x = 0; x < width; x++) {
894 /* TODO: is un-premultiplying alpha the right thing to do?
895 dest[pos2].r = data[pos + 1];
896 dest[pos2].g = data[pos + 2];
897 dest[pos2].b = data[pos + 3];*/
898 dest[pos2].r = ((int)data[pos + 1]*255)/(int)data[pos+0];
899 dest[pos2].g = ((int)data[pos + 2]*255)/(int)data[pos+0];
900 dest[pos2].b = ((int)data[pos + 3]*255)/(int)data[pos+0];
901 dest[pos2].a = data[pos + 0]; //alpha
907 for (x = 0; x < srcwidth; x++) {
908 dest[pos2] = palette[data[pos++]];
912 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
922 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
923 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
933 swf_SetU32(tag, 0); //placeholder
934 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
935 for (y = 0; y < height; y++) {
936 U8 scanline[3 * width];
938 for (x = 0; x < width; x++) {
939 scanline[p++] = bitmap[width * y + x].r;
940 scanline[p++] = bitmap[width * y + x].g;
941 scanline[p++] = bitmap[width * y + x].b;
943 swf_SetJPEGBitsLine(jpeg, scanline);
945 swf_SetJPEGBitsFinish(jpeg);
946 PUT32(&tag->data[pos], tag->len - pos - 4);
948 data = rfx_alloc(OUTBUFFER_SIZE);
949 memset(&zs, 0x00, sizeof(z_stream));
951 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
952 fprintf(stderr, "rfxswf: zlib compression failed");
957 zs.avail_out = OUTBUFFER_SIZE;
959 for (y = 0; y < height; y++) {
962 for (x = 0; x < width; x++) {
963 scanline[p++] = bitmap[width * y + x].a;
966 zs.next_in = scanline;
969 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
970 fprintf(stderr, "rfxswf: zlib compression failed");
973 if (zs.next_out != data) {
974 swf_SetBlock(tag, data, zs.next_out - data);
976 zs.avail_out = OUTBUFFER_SIZE;
985 int ret = deflate(&zs, Z_FINISH);
986 if (ret != Z_OK && ret != Z_STREAM_END) {
987 fprintf(stderr, "rfxswf: zlib compression failed");
990 if (zs.next_out != data) {
991 swf_SetBlock(tag, data, zs.next_out - data);
993 zs.avail_out = OUTBUFFER_SIZE;
995 if (ret == Z_STREAM_END) {
1005 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1007 TAG *tag1 = 0, *tag2 = 0;
1008 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1010 /* try lossless image */
1011 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1012 swf_SetU16(tag1, bitid);
1013 swf_SetLosslessImage(tag1, mem, width, height);
1015 /* try jpeg image */
1017 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1018 swf_SetU16(tag2, bitid);
1019 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1021 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1022 swf_SetU16(tag2, bitid);
1023 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1026 if(tag1 && tag1->len < tag2->len) {
1027 /* use the zlib version- it's smaller */
1029 if(tag) tag->next = tag1;
1031 swf_DeleteTag(tag2);
1033 /* use the jpeg version- it's smaller */
1035 if(tag) tag->next = tag2;
1037 swf_DeleteTag(tag1);
1044 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1048 swf_SetTagPos(tag, 2); // id is 2 bytes
1050 if (tag->id == ST_DEFINEBITSJPEG ||
1051 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1053 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1055 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1059 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1060 tag->id == ST_DEFINEBITSLOSSLESS2) {
1062 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1064 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1068 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1069 swf_TagGetName(tag));
1073 #undef OUTBUFFER_SIZE
1076 void swf_RemoveJPEGTables(SWF * swf)
1078 TAG *tag = swf->firstTag;
1079 TAG *tables_tag = 0;
1081 if (tag->id == ST_JPEGTABLES) {
1090 tag = swf->firstTag;
1092 if (tag->id == ST_DEFINEBITSJPEG) {
1094 void *data = rfx_alloc(len);
1095 swf_GetBlock(tag, data, tag->len);
1096 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1097 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1098 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1099 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1104 if (swf->firstTag == tables_tag)
1105 swf->firstTag = tables_tag->next;
1106 swf_DeleteTag(tables_tag);
1109 typedef struct scale_lookup {
1111 unsigned int weight;
1114 typedef struct rgba_int {
1115 unsigned int r,g,b,a;
1118 static int bicubic = 0;
1120 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1122 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1123 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1124 double fx = ((double)width)/((double)newwidth);
1127 scale_lookup_t*p_x = lookupx;
1129 if(newwidth<=width) {
1130 for(x=0;x<newwidth;x++) {
1131 double ex = px + fx;
1132 int fromx = (int)px;
1134 double rem = fromx+1-px;
1135 int i = (int)(256/fx);
1136 int xweight = (int)(rem*256/fx);
1140 if(tox>=width) tox = width-1;
1141 for(xx=fromx;xx<=tox;xx++) {
1142 if(xx==fromx && xx==tox) p_x->weight = 256;
1143 else if(xx==fromx) p_x->weight = xweight;
1144 else if(xx==tox) p_x->weight = 256-w;
1145 else p_x->weight = i;
1153 for(x=0;x<newwidth;x++) {
1155 int ix2 = ((int)px)+1;
1157 if(ix2>=width) ix2=width-1;
1161 p_x[0].weight = (int)(256*(1-r));
1163 p_x[1].weight = 256-p_x[0].weight;
1169 lblockx[newwidth] = p_x;
1172 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1176 scale_lookup_t *p, **lblockx,**lblocky;
1179 if(newwidth<1 || newheight<1)
1182 /* this is bad because this scaler doesn't yet handle monochrome
1183 images with 2 colors in a way that the final image hasn't more
1185 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2)
1186 fprintf(stderr, "Warning: scaling monochrome image\n");
1188 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1189 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1191 lblockx = make_scale_lookup(width, newwidth);
1192 lblocky = make_scale_lookup(height, newheight);
1194 for(p=lblocky[0];p<lblocky[newheight];p++)
1197 for(y=0;y<newheight;y++) {
1198 RGBA*destline = &newdata[y*newwidth];
1200 /* create lookup table for y */
1201 rgba_int_t*l = tmpline;
1202 scale_lookup_t*p_y,*p_x;
1203 memset(tmpline, 0, width*sizeof(rgba_int_t));
1204 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1205 RGBA*line = &data[p_y->pos];
1207 int weight = p_y->weight;
1208 for(x=0;x<width;x++) {
1209 tmpline[x].r += line[x].r*weight;
1210 tmpline[x].g += line[x].g*weight;
1211 tmpline[x].b += line[x].b*weight;
1212 tmpline[x].a += line[x].a*weight;
1216 /* process x direction */
1218 for(x=0;x<newwidth;x++) {
1219 unsigned int r=0,g=0,b=0,a=0;
1220 scale_lookup_t*p_x_to = lblockx[x+1];
1222 rgba_int_t* col = &tmpline[p_x->pos];
1223 unsigned int weight = p_x->weight;
1229 } while (p_x<p_x_to);
1231 destline->r = r >> 16;
1232 destline->g = g >> 16;
1233 destline->b = b >> 16;
1234 destline->a = a >> 16;