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;
46 int palette_overflow = 0;
49 U32 col32 = *(U32*)&img[t];
51 for(i=0;i<palsize;i++) {
52 if(col32 == *(U32*)&pal[i])
66 memcpy(palette, pal, palsize*sizeof(RGBA));
72 typedef struct _JPEGDESTMGR {
73 struct jpeg_destination_mgr mgr;
76 struct jpeg_compress_struct cinfo;
77 struct jpeg_error_mgr jerr;
78 } JPEGDESTMGR, *LPJPEGDESTMGR;
80 // Destination manager callbacks
82 static void RFXSWF_init_destination(j_compress_ptr cinfo)
84 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
85 dmgr->buffer = (JOCTET *) rfx_alloc(OUTBUFFER_SIZE);
86 dmgr->mgr.next_output_byte = dmgr->buffer;
87 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
90 static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
92 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
93 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer, OUTBUFFER_SIZE);
94 dmgr->mgr.next_output_byte = dmgr->buffer;
95 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
99 static void RFXSWF_term_destination(j_compress_ptr cinfo)
101 JPEGDESTMGR *dmgr = (JPEGDESTMGR *) cinfo->dest;
102 swf_SetBlock(dmgr->t, (U8 *) dmgr->buffer,
103 OUTBUFFER_SIZE - dmgr->mgr.free_in_buffer);
104 rfx_free(dmgr->buffer);
105 dmgr->mgr.free_in_buffer = 0;
108 JPEGBITS *swf_SetJPEGBitsStart(TAG * t, int width, int height, int quality)
112 // redirect compression lib output to local SWF Tag structure
114 jpeg = (JPEGDESTMGR *) rfx_calloc(sizeof(JPEGDESTMGR));
116 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
118 jpeg_create_compress(&jpeg->cinfo);
120 jpeg->mgr.init_destination = RFXSWF_init_destination;
121 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
122 jpeg->mgr.term_destination = RFXSWF_term_destination;
126 jpeg->cinfo.dest = (struct jpeg_destination_mgr *) jpeg;
130 jpeg->cinfo.image_width = width;
131 jpeg->cinfo.image_height = height;
132 jpeg->cinfo.input_components = 3;
133 jpeg->cinfo.in_color_space = JCS_RGB;
135 jpeg_set_defaults(&jpeg->cinfo);
136 jpeg_set_quality(&jpeg->cinfo, quality, TRUE);
138 // write tables to SWF
140 jpeg_write_tables(&jpeg->cinfo);
142 // compess image to SWF
144 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
145 jpeg_start_compress(&jpeg->cinfo, FALSE);
147 return (JPEGBITS *) jpeg;
150 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits, U8 ** data, int n)
152 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
155 jpeg_write_scanlines(&jpeg->cinfo, data, n);
159 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits, U8 * data)
161 return swf_SetJPEGBitsLines(jpegbits, &data, 1);
164 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
166 JPEGDESTMGR *jpeg = (JPEGDESTMGR *) jpegbits;
169 jpeg_finish_compress(&jpeg->cinfo);
174 void swf_SetJPEGBits2(TAG * tag, U16 width, U16 height, RGBA * bitmap,
179 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
180 for (y = 0; y < height; y++) {
181 U8 scanline[3 * width];
183 for (x = 0; x < width; x++) {
184 scanline[p++] = bitmap[width * y + x].r;
185 scanline[p++] = bitmap[width * y + x].g;
186 scanline[p++] = bitmap[width * y + x].b;
188 swf_SetJPEGBitsLine(jpeg, scanline);
190 swf_SetJPEGBitsFinish(jpeg);
193 void swf_GetJPEGSize(char *fname, int *width, int *height)
195 struct jpeg_decompress_struct cinfo;
196 struct jpeg_error_mgr jerr;
200 cinfo.err = jpeg_std_error(&jerr);
201 jpeg_create_decompress(&cinfo);
202 if ((fi = fopen(fname, "rb")) == NULL) {
203 fprintf(stderr, "rfxswf: file open error\n");
206 jpeg_stdio_src(&cinfo, fi);
207 jpeg_read_header(&cinfo, TRUE);
208 *width = cinfo.image_width;
209 *height = cinfo.image_height;
210 jpeg_destroy_decompress(&cinfo);
214 int swf_SetJPEGBits(TAG * t, char *fname, int quality)
216 struct jpeg_decompress_struct cinfo;
217 struct jpeg_error_mgr jerr;
222 cinfo.err = jpeg_std_error(&jerr);
223 jpeg_create_decompress(&cinfo);
225 if ((f = fopen(fname, "rb")) == NULL) {
226 fprintf(stderr, "rfxswf: file open error\n");
230 jpeg_stdio_src(&cinfo, f);
231 jpeg_read_header(&cinfo, TRUE);
232 jpeg_start_decompress(&cinfo);
235 swf_SetJPEGBitsStart(t, cinfo.output_width, cinfo.output_height,
237 scanline = (U8 *) rfx_alloc(4 * cinfo.output_width);
242 if (cinfo.out_color_space == JCS_GRAYSCALE) {
243 for (y = 0; y < cinfo.output_height; y++) {
245 jpeg_read_scanlines(&cinfo, &js, 1);
246 for (x = cinfo.output_width - 1; x >= 0; x--) {
247 js[x * 3] = js[x * 3 + 1] = js[x * 3 + 2] = js[x];
249 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
251 } else if (cinfo.out_color_space == JCS_RGB) {
252 for (y = 0; y < cinfo.output_height; y++) {
253 jpeg_read_scanlines(&cinfo, &js, 1);
254 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
256 } else if (cinfo.out_color_space == JCS_YCCK) {
258 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
260 } else if (cinfo.out_color_space == JCS_YCbCr) {
261 for (y = 0; y < cinfo.output_height; y++) {
263 for (x = 0; x < cinfo.output_width; x++) {
264 int y = js[x * 3 + 0];
265 int u = js[x * 3 + 1];
266 int v = js[x * 3 + 1];
267 js[x * 3 + 0] = y + ((360 * (v - 128)) >> 8);
269 y - ((88 * (u - 128) + 183 * (v - 128)) >> 8);
270 js[x * 3 + 2] = y + ((455 * (u - 128)) >> 8);
273 } else if (cinfo.out_color_space == JCS_CMYK) {
274 for (y = 0; y < cinfo.output_height; y++) {
276 jpeg_read_scanlines(&cinfo, &js, 1);
277 /* This routine seems to work for now-
278 It's a mixture of 3 different
279 CMYK->RGB conversion routines I found in the
280 web. (which all produced garbage)
281 I'm happily accepting suggestions. (mk) */
282 for (x = 0; x < cinfo.output_width; x++) {
283 int white = 255 - js[x * 4 + 3];
284 js[x * 3 + 0] = white - ((js[x * 4] * white) >> 8);
285 js[x * 3 + 1] = white - ((js[x * 4 + 1] * white) >> 8);
286 js[x * 3 + 2] = white - ((js[x * 4 + 2] * white) >> 8);
288 swf_SetJPEGBitsLines(out, (U8 **) & js, 1);
293 swf_SetJPEGBitsFinish(out);
294 jpeg_finish_decompress(&cinfo);
300 /* jpeg_source_mgr functions */
301 static void tag_init_source(struct jpeg_decompress_struct *cinfo)
303 TAG *tag = (TAG *) cinfo->client_data;
304 swf_SetTagPos(tag, 2);
305 cinfo->src->bytes_in_buffer = 0;
307 static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
309 TAG *tag = (TAG *) cinfo->client_data;
310 if (tag->data[tag->pos + 0] == 0xff &&
311 tag->data[tag->pos + 1] == 0xd9 &&
312 tag->data[tag->pos + 2] == 0xff &&
313 tag->data[tag->pos + 3] == 0xd8) {
316 if (tag->pos >= tag->len) {
317 cinfo->src->next_input_byte = 0;
318 cinfo->src->bytes_in_buffer = 0;
321 cinfo->src->next_input_byte = &tag->data[tag->pos];
322 cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
326 static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
328 TAG *tag = (TAG *) cinfo->client_data;
329 cinfo->src->next_input_byte = 0;
330 cinfo->src->bytes_in_buffer = 0;
333 static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
335 return jpeg_resync_to_restart(cinfo, desired);
337 static void tag_term_source(struct jpeg_decompress_struct *cinfo)
339 TAG *tag = (TAG *) cinfo->client_data;
341 RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
343 struct jpeg_decompress_struct cinfo;
344 struct jpeg_error_mgr jerr;
345 struct jpeg_source_mgr mgr;
351 if (tag->id == ST_DEFINEBITSJPEG) {
353 "rfxswf: extracting from definebitsjpeg not yet supported");
356 if (tag->id == ST_DEFINEBITSJPEG3) {
358 "rfxswf: extracting from definebitsjpeg3 not yet supported");
362 cinfo.err = jpeg_std_error(&jerr);
363 jpeg_create_decompress(&cinfo);
365 cinfo.client_data = (void *) tag;
367 cinfo.src->init_source = tag_init_source;
368 cinfo.src->fill_input_buffer = tag_fill_input_buffer;
369 cinfo.src->skip_input_data = tag_skip_input_data;
370 cinfo.src->resync_to_restart = jpeg_resync_to_restart;
371 cinfo.src->term_source = tag_term_source;
372 cinfo.out_color_space = JCS_RGB;
374 jpeg_read_header(&cinfo, TRUE);
375 *width = cinfo.image_width;
376 *height = cinfo.image_height;
378 rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
380 jpeg_start_decompress(&cinfo);
381 for (y = 0; y < cinfo.output_height; y++) {
382 RGBA *line = &dest[y * cinfo.image_width];
383 U8 *to = (U8 *) line;
385 jpeg_read_scanlines(&cinfo, &to, 1);
386 for (x = cinfo.output_width - 1; x >= 0; --x) {
387 int r = to[x * 3 + 0];
388 int g = to[x * 3 + 1];
389 int b = to[x * 3 + 2];
397 jpeg_finish_decompress(&cinfo);
399 jpeg_destroy_decompress(&cinfo);
403 #endif // HAVE_JPEGLIB
405 // Lossless compression texture based on zlib
409 int RFXSWF_deflate_wraper(TAG * t, z_stream * zs, boolean finish)
411 U8 *data = rfx_alloc(OUTBUFFER_SIZE);
413 zs->avail_out = OUTBUFFER_SIZE;
415 int status = deflate(zs, Z_NO_FLUSH);
417 if (status != Z_OK) {
418 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
423 if (zs->next_out != data) {
424 swf_SetBlock(t, data, zs->next_out - data);
426 zs->avail_out = OUTBUFFER_SIZE;
429 if (zs->avail_in == 0)
439 int status = deflate(zs, Z_FINISH);
440 if (status != Z_OK && status != Z_STREAM_END) {
441 fprintf(stderr, "rfxswf: zlib compression error (%i)\n", status);
446 if (zs->next_out != data) {
447 swf_SetBlock(t, data, zs->next_out - data);
449 zs->avail_out = OUTBUFFER_SIZE;
452 if (status == Z_STREAM_END)
460 int swf_SetLosslessBits(TAG * t, U16 width, U16 height, void *bitmap, U8 bitmap_flags)
465 switch (bitmap_flags) {
467 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
469 bps = BYTES_PER_SCANLINE(sizeof(U16) * width);
475 fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags);
479 swf_SetU8(t, bitmap_flags);
480 swf_SetU16(t, width);
481 swf_SetU16(t, height);
486 memset(&zs, 0x00, sizeof(z_stream));
490 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
491 zs.avail_in = bps * height;
494 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
499 res = -3; // zlib error
504 int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
507 int bps = BYTES_PER_SCANLINE(width);
510 if (!pal) // create default palette for grayscale images
513 pal = rfx_alloc(256 * sizeof(RGBA));
514 for (i = 0; i < 256; i++) {
515 pal[i].r = pal[i].g = pal[i].b = i;
521 if ((ncolors < 2) || (ncolors > 256) || (!t)) {
522 fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
524 return -1; // parameter error
527 swf_SetU8(t, BMF_8BIT);
528 swf_SetU16(t, width);
529 swf_SetU16(t, height);
530 swf_SetU8(t, ncolors - 1); // number of pal entries
535 memset(&zs, 0x00, sizeof(z_stream));
539 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
540 U8 *zpal; // compress palette
541 if ((zpal = rfx_alloc(ncolors * 4))) {
545 /* be careful with ST_DEFINEBITSLOSSLESS2, because
546 the Flash player produces great bugs if you use too many
547 alpha colors in your palette. The only sensible result that
548 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
549 make transparent parts in sprites. That's the cause why alpha
550 handling is implemented in lossless routines of rfxswf.
552 Indeed: I haven't understood yet how flash player handles
553 alpha values different from 0 and 0xff in lossless bitmaps...
556 if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
558 for (i = 0; i < ncolors; i++) {
565 zs.avail_in = 4 * ncolors;
567 for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
574 zs.avail_in = 3 * ncolors;
579 if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
584 zs.avail_in = (bps * height * sizeof(U8));
586 if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
593 res = -2; // memory error
595 res = -3; // zlib error
604 int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
606 return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
609 void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
611 int hasalpha = swf_ImageHasAlpha(data, width, height);
613 tag->id = ST_DEFINEBITSLOSSLESS;
615 tag->id = ST_DEFINEBITSLOSSLESS2;
616 /* TODO: premultiply alpha? */
618 int num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
619 if(num>1 && num<=256) {
620 RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
621 swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
622 int width2 = BYTES_PER_SCANLINE(width);
623 U8*data2 = (U8*)malloc(width2*height);
624 int len = width*height;
627 for(y=0;y<height;y++) {
628 RGBA*src = &data[width*y];
629 U8*dest = &data2[width2*y];
630 for(x=0;x<width;x++) {
633 if(*(U32*)&col == *(U32*)&palette[r]) {
639 fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
640 col.r, col.g, col.b, col.a, num);
645 swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
649 swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
653 RGBA *swf_DefineLosslessBitsTagToImage(TAG * tag, int *dwidth, int *dheight)
655 int id, format, height, width, pos;
656 U32 datalen, datalen2;
661 char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
666 if (tag->id != ST_DEFINEBITSLOSSLESS &&
667 tag->id != ST_DEFINEBITSLOSSLESS2) {
668 fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",
672 swf_SetTagPos(tag, 0);
673 id = swf_GetU16(tag);
674 format = swf_GetU8(tag);
681 if (format != 3 && format != 5) {
684 "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",
687 fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n",
691 *dwidth = width = swf_GetU16(tag);
692 *dheight = height = swf_GetU16(tag);
694 dest = rfx_alloc(sizeof(RGBA) * width * height);
697 cols = swf_GetU8(tag) + 1;
702 datalen = (width * height * bpp / 8 + cols * 8);
707 data = rfx_alloc(datalen);
709 uncompress(data, &datalen, &tag->data[tag->pos],
710 tag->len - tag->pos);
711 } while (error == Z_BUF_ERROR);
713 fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id);
719 palette = (RGBA *) rfx_alloc(cols * sizeof(RGBA));
720 for (t = 0; t < cols; t++) {
721 palette[t].r = data[pos++];
722 palette[t].g = data[pos++];
723 palette[t].b = data[pos++];
725 palette[t].a = data[pos++];
730 for (y = 0; y < height; y++) {
731 int srcwidth = width * (bpp / 8);
734 // 32 bit to 24 bit "conversion"
735 for (x = 0; x < width; x++) {
736 dest[pos2].r = data[pos + 1];
737 dest[pos2].g = data[pos + 2];
738 dest[pos2].b = data[pos + 3];
741 pos += 4; //ignore padding byte
744 for (x = 0; x < width; x++) {
745 /* TODO: un-premultiply alpha? */
746 dest[pos2].r = data[pos + 1];
747 dest[pos2].g = data[pos + 2];
748 dest[pos2].b = data[pos + 3];
749 dest[pos2].a = data[pos + 0]; //alpha
755 for (x = 0; x < srcwidth; x++) {
756 dest[pos2] = palette[data[pos++]];
760 pos += ((srcwidth + 3) & ~3) - srcwidth; //align
770 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
771 int swf_SetJPEGBits3(TAG * tag, U16 width, U16 height, RGBA * bitmap, int quality)
781 swf_SetU32(tag, 0); //placeholder
782 jpeg = swf_SetJPEGBitsStart(tag, width, height, quality);
783 for (y = 0; y < height; y++) {
784 U8 scanline[3 * width];
786 for (x = 0; x < width; x++) {
787 scanline[p++] = bitmap[width * y + x].r;
788 scanline[p++] = bitmap[width * y + x].g;
789 scanline[p++] = bitmap[width * y + x].b;
791 swf_SetJPEGBitsLine(jpeg, scanline);
793 swf_SetJPEGBitsFinish(jpeg);
794 PUT32(&tag->data[pos], tag->len - pos - 4);
796 data = rfx_alloc(OUTBUFFER_SIZE);
797 memset(&zs, 0x00, sizeof(z_stream));
799 if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
800 fprintf(stderr, "rfxswf: zlib compression failed");
805 zs.avail_out = OUTBUFFER_SIZE;
807 for (y = 0; y < height; y++) {
810 for (x = 0; x < width; x++) {
811 scanline[p++] = bitmap[width * y + x].a;
814 zs.next_in = scanline;
817 if (deflate(&zs, Z_NO_FLUSH) != Z_OK) {
818 fprintf(stderr, "rfxswf: zlib compression failed");
821 if (zs.next_out != data) {
822 swf_SetBlock(tag, data, zs.next_out - data);
824 zs.avail_out = OUTBUFFER_SIZE;
833 int ret = deflate(&zs, Z_FINISH);
834 if (ret != Z_OK && ret != Z_STREAM_END) {
835 fprintf(stderr, "rfxswf: zlib compression failed");
838 if (zs.next_out != data) {
839 swf_SetBlock(tag, data, zs.next_out - data);
841 zs.avail_out = OUTBUFFER_SIZE;
843 if (ret == Z_STREAM_END) {
854 RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
857 if (tag->id == ST_DEFINEBITSJPEG ||
858 tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
860 return swf_JPEG2TagToImage(tag, dwidth, dheight);
862 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
866 if (tag->id == ST_DEFINEBITSLOSSLESS ||
867 tag->id == ST_DEFINEBITSLOSSLESS2) {
869 return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight);
871 fprintf(stderr, "rfxswf: Error: No JPEG library compiled in");
875 fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id,
876 swf_TagGetName(tag));
880 #undef OUTBUFFER_SIZE
883 void swf_RemoveJPEGTables(SWF * swf)
885 TAG *tag = swf->firstTag;
888 if (tag->id == ST_JPEGTABLES) {
899 if (tag->id == ST_DEFINEBITSJPEG) {
900 void *data = rfx_alloc(tag->len);
901 swf_GetBlock(tag, data, tag->len);
902 swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
903 swf_SetBlock(tag, tables_tag->data, tables_tag->len);
904 swf_SetBlock(tag, data, tag->len);
909 if (swf->firstTag == tables_tag)
910 swf->firstTag = tables_tag->next;
911 swf_DeleteTag(tables_tag);
914 typedef struct scale_lookup {
919 typedef struct rgba_int {
920 unsigned int r,g,b,a;
923 static int bicubic = 0;
925 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
927 scale_lookup_t*lookupx = malloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
928 scale_lookup_t**lblockx = (scale_lookup_t**)malloc((newwidth+1)*sizeof(scale_lookup_t**));
929 double fx = ((double)width)/((double)newwidth);
932 scale_lookup_t*p_x = lookupx;
934 if(newwidth<=width) {
935 for(x=0;x<newwidth;x++) {
940 double rem = fromx+1-px;
941 int i = (int)(256/fx);
942 int xweight = (int)(rem*256/fx);
945 if(tox>=width) tox = width-1;
946 for(xx=fromx;xx<=tox;xx++) {
947 if(xx==fromx && xx==tox) p_x->weight = 256;
948 else if(xx==fromx) p_x->weight = xweight;
949 else if(xx==tox) p_x->weight = 256-w;
950 else p_x->weight = i;
958 for(x=0;x<newwidth;x++) {
961 int ix2 = ((int)px)+1;
962 if(ix2>=width) ix2=width-1;
966 p_x[0].weight = (int)(256*(1-r));
968 p_x[1].weight = 256-p_x[0].weight;
974 lblockx[newwidth] = p_x;
978 RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
980 if(newwidth<2 || newheight<2)
983 RGBA* newdata= (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
984 scale_lookup_t *p, **lblockx,**lblocky;
985 rgba_int_t*tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
987 lblockx = make_scale_lookup(width, newwidth);
988 lblocky = make_scale_lookup(height, newheight);
990 for(p=lblocky[0];p<lblocky[newheight];p++)
993 for(y=0;y<newheight;y++) {
994 RGBA*destline = &newdata[y*newwidth];
996 /* create lookup table for y */
997 rgba_int_t*l = tmpline;
999 memset(tmpline, 0, width*sizeof(rgba_int_t));
1000 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
1001 RGBA*line = &data[p_y->pos];
1003 int weight = p_y->weight;
1004 for(x=0;x<width;x++) {
1005 tmpline[x].r += line[x].r*weight;
1006 tmpline[x].g += line[x].g*weight;
1007 tmpline[x].b += line[x].b*weight;
1008 tmpline[x].a += line[x].a*weight;
1012 /* process x direction */
1013 scale_lookup_t*p_x = lblockx[0];
1014 for(x=0;x<newwidth;x++) {
1015 unsigned int r=0,g=0,b=0,a=0;
1016 scale_lookup_t*p_x_to = lblockx[x+1];
1018 rgba_int_t* col = &tmpline[p_x->pos];
1019 unsigned int weight = p_x->weight;
1025 } while (p_x<p_x_to);
1027 destline->r = r >> 16;
1028 destline->g = g >> 16;
1029 destline->b = b >> 16;
1030 destline->a = a >> 16;