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 typedef struct _JPEGFILEMGR {
404 struct jpeg_destination_mgr mgr;
406 struct jpeg_compress_struct* cinfo;
407 struct jpeg_error_mgr* jerr;
411 static void file_init_destination(j_compress_ptr cinfo)
413 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
414 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
416 fmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE);
419 fprintf(stderr, "Out of memory!\n");
423 dmgr->next_output_byte = fmgr->buffer;
424 dmgr->free_in_buffer = OUTBUFFER_SIZE;
427 static boolean file_empty_output_buffer(j_compress_ptr cinfo)
429 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
430 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
433 fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
435 dmgr->next_output_byte = fmgr->buffer;
436 dmgr->free_in_buffer = OUTBUFFER_SIZE;
440 static void file_term_destination(j_compress_ptr cinfo)
442 JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
443 struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
446 fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
448 rfx_free(fmgr->buffer);
450 dmgr->free_in_buffer = 0;
451 dmgr->next_output_byte = 0;
454 void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
457 struct jpeg_compress_struct cinfo;
458 struct jpeg_error_mgr jerr;
459 unsigned char*data2 = 0;
462 FILE*fi = fopen(filename, "wb");
465 sprintf(buf, "rfxswf: Couldn't create %s", filename);
469 data2 = rfx_calloc(width*3);
471 memset(&cinfo, 0, sizeof(cinfo));
472 memset(&jerr, 0, sizeof(jerr));
473 memset(&fmgr, 0, sizeof(fmgr));
474 cinfo.err = jpeg_std_error(&jerr);
475 jpeg_create_compress(&cinfo);
477 fmgr.mgr.init_destination = file_init_destination;
478 fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
479 fmgr.mgr.term_destination = file_term_destination;
483 cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
487 cinfo.image_width = width;
488 cinfo.image_height = height;
489 cinfo.input_components = 3;
490 cinfo.in_color_space = JCS_RGB;
491 jpeg_set_defaults(&cinfo);
492 cinfo.dct_method = JDCT_IFAST;
493 jpeg_set_quality(&cinfo,quality,TRUE);
495 //jpeg_write_tables(&cinfo);
496 //jpeg_suppress_tables(&cinfo, TRUE);
497 jpeg_start_compress(&cinfo, FALSE);
499 for(y=0;y<height;y++) {
501 RGBA*src = &pixels[y*width];
502 for(x=0;x<width;x++) {
503 data2[x*3+0] = src[x].r;
504 data2[x*3+1] = src[x].g;
505 data2[x*3+2] = src[x].b;
507 jpeg_write_scanlines(&cinfo, &data2, 1);
510 jpeg_finish_compress(&cinfo);
511 jpeg_destroy_compress(&cinfo);
516 /* jpeg_source_mgr functions */
517 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
519 TAG *tag = (TAG *) cinfo->client_data;
520 if (tag->id == ST_DEFINEBITSJPEG3) {
521 swf_SetTagPos(tag, 6);
523 swf_SetTagPos(tag, 2);
525 cinfo->src->bytes_in_buffer = 0;
527 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
529 TAG *tag = (TAG *) cinfo->client_data;
530 if (tag->data[tag->pos + 0] == 0xff &&
531 tag->data[tag->pos + 1] == 0xd9 &&
532 tag->data[tag->pos + 2] == 0xff &&
533 tag->data[tag->pos + 3] == 0xd8) {
536 if (tag->pos >= tag->len) {
537 cinfo->src->next_input_byte = 0;
538 cinfo->src->bytes_in_buffer = 0;
541 cinfo->src->next_input_byte = &tag->data[tag->pos];
542 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
546 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
548 TAG *tag = (TAG *) cinfo->client_data;
549 cinfo->src->next_input_byte = 0;
550 cinfo->src->bytes_in_buffer = 0;
553 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
555 return jpeg_resync_to_restart(cinfo, desired);
557 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
559 TAG *tag = (TAG *) cinfo->client_data;
561 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
563 struct jpeg_decompress_struct cinfo;
564 struct jpeg_error_mgr jerr;
565 struct jpeg_source_mgr mgr;
573 if (tag->id == ST_DEFINEBITSJPEG) {
574 fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
577 if (tag->id == ST_DEFINEBITSJPEG3) {
579 offset = swf_GetU32(tag);
580 oldtaglen = tag->len;
583 fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
588 cinfo.err = jpeg_std_error(&jerr);
589 jpeg_create_decompress(&cinfo);
591 cinfo.client_data = (void *) tag;
593 cinfo.src->init_source = tag_init_source;
594 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
595 cinfo.src->skip_input_data = tag_skip_input_data;
596 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
597 cinfo.src->term_source = tag_term_source;
598 cinfo.out_color_space = JCS_RGB;
600 jpeg_read_header(&cinfo, TRUE);
601 *width = cinfo.image_width;
602 *height = cinfo.image_height;
604 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
606 jpeg_start_decompress(&cinfo);
607 for (y = 0; y < cinfo.output_height; y++) {
608 RGBA *line = &dest[y * cinfo.image_width];
609 U8 *to = (U8 *) line;
611 jpeg_read_scanlines(&cinfo, &to, 1);
612 for (x = cinfo.output_width - 1; x >= 0; --x) {
613 int r = to[x * 3 + 0];
614 int g = to[x * 3 + 1];
615 int b = to[x * 3 + 2];
623 jpeg_finish_decompress(&cinfo);
625 jpeg_destroy_decompress(&cinfo);
629 U32 datalen = cinfo.output_width*cinfo.output_height;
630 U8* alphadata = (U8*)rfx_alloc(datalen);
632 tag->len = oldtaglen;
633 swf_SetTagPos(tag, 6+offset);
634 error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
636 fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
639 for(y=0;y<cinfo.output_height;y++) {
640 RGBA*line = &dest[y*cinfo.output_width];
641 U8*aline = &alphadata[y*cinfo.output_width];
643 for(x=0;x<cinfo.output_width;x++) {
644 line[x].a = aline[x];
653 #endif // HAVE_JPEGLIB
655 // Lossless compression texture based on zlib
659 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
661 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
663 zs->avail_out = OUTBUFFER_SIZE;
665 int status = deflate(zs, Z_NO_FLUSH);
667 if (status != Z_OK) {
668 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
673 if (zs->next_out != data) {
674 swf_SetBlock(t, data, zs->next_out - data);
676 zs->avail_out = OUTBUFFER_SIZE;
679 if (zs->avail_in == 0)
689 int status = deflate(zs, Z_FINISH);
690 if (status != Z_OK && status != Z_STREAM_END) {
691 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
696 if (zs->next_out != data) {
697 swf_SetBlock(t, data, zs->next_out - data);
699 zs->avail_out = OUTBUFFER_SIZE;
702 if (status == Z_STREAM_END)
710 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
715 switch (bitmap_flags) {
717 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
719 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
725 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
729 swf_SetU8(t, bitmap_flags);
730 swf_SetU16(t, width);
731 swf_SetU16(t, height);
736 memset(&zs, 0x00, sizeof(z_stream));
740 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
741 zs.avail_in = bps * height;
744 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
749 res = -3; // zlib error
754 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
757 int bps = BYTES_PER_SCANLINE(width);
760 if (!pal) // create default palette for grayscale images
763 pal = rfx_alloc(256 * sizeof(RGBA));
764 for (i = 0; i < 256; i++) {
765 pal[i].r = pal[i].g = pal[i].b = i;
771 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
772 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
774 return -1; // parameter error
777 swf_SetU8(t, BMF_8BIT);
778 swf_SetU16(t, width);
779 swf_SetU16(t, height);
780 swf_SetU8(t, ncolors - 1); // number of pal entries
785 memset(&zs, 0x00, sizeof(z_stream));
789 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
790 U8 *zpal; // compress palette
791 if ((zpal = rfx_alloc(ncolors * 4))) {
795 /* be careful with ST_DEFINEBITSLOSSLESS2, because
796 the Flash player produces great bugs if you use too many
797 alpha colors in your palette. The only sensible result that
798 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
799 make transparent parts in sprites. That's the cause why alpha
800 handling is implemented in lossless routines of rfxswf.
802 Indeed: I haven't understood yet how flash player handles
803 alpha values different from 0 and 0xff in lossless bitmaps...
806 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
808 for (i = 0; i < ncolors; i++) {
815 zs.avail_in = 4 * ncolors;
817 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
824 zs.avail_in = 3 * ncolors;
829 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
834 zs.avail_in = (bps * height * sizeof(U8));
836 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
843 res = -2; // memory error
845 res = -3; // zlib error
854 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
856 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
859 void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
861 int num = width*height;
864 data[t].r = ((int)data[t].r*data[t].a)/255;
865 data[t].g = ((int)data[t].g*data[t].a)/255;
866 data[t].b = ((int)data[t].b*data[t].a)/255;
870 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
872 int hasalpha = swf_ImageHasAlpha(data, width, height);
875 tag->id = ST_DEFINEBITSLOSSLESS;
877 tag->id = ST_DEFINEBITSLOSSLESS2;
878 swf_PreMultiplyAlpha(data, width, height);
880 num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
881 if(num>1 && num<=256) {
882 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
883 int width2 = BYTES_PER_SCANLINE(width);
884 U8*data2 = (U8*)malloc(width2*height);
885 int len = width*height;
888 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
889 for(y=0;y<height;y++) {
890 RGBA*src = &data[width*y];
891 U8*dest = &data2[width2*y];
892 for(x=0;x<width;x++) {
895 if(*(U32*)&col == *(U32*)&palette[r]) {
901 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
902 col.r, col.g, col.b, col.a, num);
907 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
911 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
915 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
917 int id, format, height, width, pos;
918 U32 datalen, datalen2;
923 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
928 if (tag->id != ST_DEFINEBITSLOSSLESS &&
929 tag->id != ST_DEFINEBITSLOSSLESS2) {
930 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
934 swf_SetTagPos(tag, 0);
935 id = swf_GetU16(tag);
936 format = swf_GetU8(tag);
943 if (format != 3 && format != 5) {
946 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
949 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
953 *dwidth = width = swf_GetU16(tag);
954 *dheight = height = swf_GetU16(tag);
956 dest = rfx_alloc(sizeof(RGBA) * width * height);
959 cols = swf_GetU8(tag) + 1;
964 datalen = (width * height * bpp / 8 + cols * 8);
969 data = rfx_alloc(datalen);
971 uncompress(data, &datalen, &tag->data[tag->pos],
972 tag->len - tag->pos);
973 } while (error == Z_BUF_ERROR);
975 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
981 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
982 for (t = 0; t < cols; t++) {
983 palette[t].r = data[pos++];
984 palette[t].g = data[pos++];
985 palette[t].b = data[pos++];
987 palette[t].a = data[pos++];
994 for (y = 0; y < height; y++) {
995 int srcwidth = width * (bpp / 8);
998 // 32 bit to 24 bit "conversion"
999 for (x = 0; x < width; x++) {
1000 dest[pos2].r = data[pos + 1];
1001 dest[pos2].g = data[pos + 2];
1002 dest[pos2].b = data[pos + 3];
1005 pos += 4; //ignore padding byte
1008 for (x = 0; x < width; x++) {
1009 /* TODO: is un-premultiplying alpha the right thing to do?
1010 dest[pos2].r = data[pos + 1];
1011 dest[pos2].g = data[pos + 2];
1012 dest[pos2].b = data[pos + 3];*/
1013 int alpha = data[pos+0];
1015 dest[pos2].r = ((int)data[pos + 1]*255)/alpha;
1016 dest[pos2].g = ((int)data[pos + 2]*255)/alpha;
1017 dest[pos2].b = ((int)data[pos + 3]*255)/alpha;
1019 dest[pos2].r = data[pos + 1];
1020 dest[pos2].g = data[pos + 2];
1021 dest[pos2].b = data[pos + 3];
1023 dest[pos2].a = data[pos + 0]; //alpha
1029 for (x = 0; x < srcwidth; x++) {
1030 dest[pos2] = palette[data[pos++]];
1034 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
1044 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
1045 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
1055 swf_SetU32(tag, 0); //placeholder
1056 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
1057 for (y = 0; y < height; y++) {
1058 U8 scanline[3 * width];
1060 for (x = 0; x < width; x++) {
1061 scanline[p++] = bitmap[width * y + x].r;
1062 scanline[p++] = bitmap[width * y + x].g;
1063 scanline[p++] = bitmap[width * y + x].b;
1065 swf_SetJPEGBitsLine(jpeg, scanline);
1067 swf_SetJPEGBitsFinish(jpeg);
1068 PUT32(&tag->data[pos], tag->len - pos - 4);
1070 data = rfx_alloc(OUTBUFFER_SIZE);
1071 memset(&zs, 0x00, sizeof(z_stream));
1073 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
1074 fprintf(stderr, "rfxswf: zlib compression failed");
1079 zs.avail_out = OUTBUFFER_SIZE;
1081 for (y = 0; y < height; y++) {
1084 for (x = 0; x < width; x++) {
1085 scanline[p++] = bitmap[width * y + x].a;
1087 zs.avail_in = width;
1088 zs.next_in = scanline;
1091 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
1092 fprintf(stderr, "rfxswf: zlib compression failed");
1095 if (zs.next_out != data) {
1096 swf_SetBlock(tag, data, zs.next_out - data);
1098 zs.avail_out = OUTBUFFER_SIZE;
1107 int ret = deflate(&zs, Z_FINISH);
1108 if (ret != Z_OK && ret != Z_STREAM_END) {
1109 fprintf(stderr, "rfxswf: zlib compression failed");
1112 if (zs.next_out != data) {
1113 swf_SetBlock(tag, data, zs.next_out - data);
1115 zs.avail_out = OUTBUFFER_SIZE;
1117 if (ret == Z_STREAM_END) {
1127 TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
1129 TAG *tag1 = 0, *tag2 = 0;
1130 int has_alpha = swf_ImageHasAlpha(mem,width,height);
1132 /* try lossless image */
1133 tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
1134 swf_SetU16(tag1, bitid);
1135 swf_SetLosslessImage(tag1, mem, width, height);
1137 /* try jpeg image */
1139 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
1140 swf_SetU16(tag2, bitid);
1141 swf_SetJPEGBits3(tag2, width, height, mem, quality);
1143 tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
1144 swf_SetU16(tag2, bitid);
1145 swf_SetJPEGBits2(tag2, width, height, mem, quality);
1148 if(tag1 && tag1->len < tag2->len) {
1149 /* use the zlib version- it's smaller */
1151 if(tag) tag->next = tag1;
1153 swf_DeleteTag(tag2);
1155 /* use the jpeg version- it's smaller */
1157 if(tag) tag->next = tag2;
1159 swf_DeleteTag(tag1);
1166 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
1170 swf_SetTagPos(tag, 2); // id is 2 bytes
1172 if (tag->id == ST_DEFINEBITSJPEG ||
1173 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
1175 return swf_JPEG2TagToImage(tag, dwidth, dheight);
1177 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1181 if (tag->id == ST_DEFINEBITSLOSSLESS ||
1182 tag->id == ST_DEFINEBITSLOSSLESS2) {
1184 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
1186 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
1190 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
1191 swf_TagGetName(tag));
1195 #undef OUTBUFFER_SIZE
1198 void swf_RemoveJPEGTables(SWF * swf)
1200 TAG *tag = swf->firstTag;
1201 TAG *tables_tag = 0;
1203 if (tag->id == ST_JPEGTABLES) {
1212 tag = swf->firstTag;
1214 if (tag->id == ST_DEFINEBITSJPEG) {
1216 void *data = rfx_alloc(len);
1217 swf_GetBlock(tag, data, tag->len);
1218 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
1219 swf_SetBlock(tag, &((U8*)data)[0], 2); //id
1220 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
1221 swf_SetBlock(tag, &((U8*)data)[2], len-2);
1226 if (swf->firstTag == tables_tag)
1227 swf->firstTag = tables_tag->next;
1228 swf_DeleteTag(tables_tag);
1231 typedef struct scale_lookup {
1233 unsigned int weight;
1236 typedef struct rgba_int {
1237 unsigned int r,g,b,a;
1240 static int bicubic = 0;
1242 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
1244 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
1245 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
1246 double fx = ((double)width)/((double)newwidth);
1249 scale_lookup_t*p_x = lookupx;
1251 if(newwidth<=width) {
1252 for(x=0;x<newwidth;x++) {
1253 double ex = px + fx;
1254 int fromx = (int)px;
1256 double rem = fromx+1-px;
1257 int i = (int)(256/fx);
1258 int xweight = (int)(rem*256/fx);
1262 if(tox>=width) tox = width-1;
1263 for(xx=fromx;xx<=tox;xx++) {
1264 if(xx==fromx && xx==tox) p_x->weight = 256;
1265 else if(xx==fromx) p_x->weight = xweight;
1266 else if(xx==tox) p_x->weight = 256-w;
1267 else p_x->weight = i;
1275 for(x=0;x<newwidth;x++) {
1277 int ix2 = ((int)px)+1;
1279 if(ix2>=width) ix2=width-1;
1283 p_x[0].weight = (int)(256*(1-r));
1285 p_x[1].weight = 256-p_x[0].weight;
1291 lblockx[newwidth] = p_x;
1294 static int monochrome_warning = 0;
1295 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
1299 scale_lookup_t *p, **lblockx,**lblocky;
1302 if(newwidth<1 || newheight<1)
1305 /* this is bad because this scaler doesn't yet handle monochrome
1306 images with 2 colors in a way that the final image hasn't more
1308 if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
1309 if(!monochrome_warning) {
1310 fprintf(stderr, "Warning: scaling monochrome image\n");
1311 monochrome_warning = 1;
1315 tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
1316 newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
1318 lblockx = make_scale_lookup(width, newwidth);
1319 lblocky = make_scale_lookup(height, newheight);
1321 for(p=lblocky[0];p<lblocky[newheight];p++)
1324 for(y=0;y<newheight;y++) {
1325 RGBA*destline = &newdata[y*newwidth];
1327 /* create lookup table for y */
1328 rgba_int_t*l = tmpline;
1329 scale_lookup_t*p_y,*p_x;
1330 memset(tmpline, 0, width*sizeof(rgba_int_t));
1331 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1332 RGBA*line = &data[p_y->pos];
1334 int weight = p_y->weight;
1335 for(x=0;x<width;x++) {
1336 tmpline[x].r += line[x].r*weight;
1337 tmpline[x].g += line[x].g*weight;
1338 tmpline[x].b += line[x].b*weight;
1339 tmpline[x].a += line[x].a*weight;
1343 /* process x direction */
1345 for(x=0;x<newwidth;x++) {
1346 unsigned int r=0,g=0,b=0,a=0;
1347 scale_lookup_t*p_x_to = lblockx[x+1];
1349 rgba_int_t* col = &tmpline[p_x->pos];
1350 unsigned int weight = p_x->weight;
1356 } while (p_x<p_x_to);
1358 destline->r = r >> 16;
1359 destline->g = g >> 16;
1360 destline->b = b >> 16;
1361 destline->a = a >> 16;