X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fmodules%2Fswfbits.c;h=f761ae079c5121d8bf58ac5a6bb136ef0792de45;hb=feddb673cf8404df91270489b130a72c65195866;hp=05b21fb671222d62264fa4985f40fd84aac2824d;hpb=fc554a43712b76d16b41ec77dd311b4a78b1ef6b;p=swftools.git diff --git a/lib/modules/swfbits.c b/lib/modules/swfbits.c index 05b21fb..f761ae0 100644 --- a/lib/modules/swfbits.c +++ b/lib/modules/swfbits.c @@ -1,152 +1,762 @@ -/* swfbits.c - - Bitmap functions (needs libjpeg) - - Extension module for the rfxswf library. - Part of the swftools package. - - Copyright (c) 2000, 2001 Rainer Böhme - - This file is distributed under the GPL, see file COPYING for details - -*/ - -#ifdef _JPEGLIB_INCLUDED_ -#define OUTBUFFER_SIZE 32768 - -typedef struct _JPEGDESTMGR -{ struct jpeg_destination_mgr mgr; - LPTAG t; - JOCTET * buffer; - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; -} JPEGDESTMGR, * LPJPEGDESTMGR; - -// Destination manager callbacks - -void swf_init_destination(j_compress_ptr cinfo) -{ LPJPEGDESTMGR dmgr = (LPJPEGDESTMGR)cinfo->dest; - dmgr->buffer = (JOCTET*)malloc(OUTBUFFER_SIZE); - dmgr->mgr.next_output_byte = dmgr->buffer; - dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE; -} - -boolean swf_empty_output_buffer(j_compress_ptr cinfo) -{ LPJPEGDESTMGR dmgr = (LPJPEGDESTMGR)cinfo->dest; - SetBlock(dmgr->t, - (U8*)dmgr->buffer, - OUTBUFFER_SIZE-dmgr->mgr.free_in_buffer); - dmgr->mgr.next_output_byte = dmgr->buffer; - dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE; -} - -void swf_term_destination(j_compress_ptr cinfo) -{ LPJPEGDESTMGR dmgr = (LPJPEGDESTMGR)cinfo->dest; - swf_empty_output_buffer(cinfo); - free(dmgr->buffer); - dmgr->mgr.free_in_buffer = 0; -} - -LPJPEGBITS SetJPEGBitsStart(LPTAG t,int width,int height,int quality) -{ - LPJPEGDESTMGR jpeg; - - // redirect compression lib output to local SWF Tag structure - - jpeg = (LPJPEGDESTMGR)malloc(sizeof(JPEGDESTMGR)); - if (!jpeg) return NULL; - - memset(jpeg,0x00,sizeof(JPEGDESTMGR)); - jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr); - - jpeg_create_compress(&jpeg->cinfo); - - jpeg->mgr.init_destination = swf_init_destination; - jpeg->mgr.empty_output_buffer = swf_empty_output_buffer; - jpeg->mgr.term_destination = swf_term_destination; - - jpeg->t = t; - - jpeg->cinfo.dest = (struct jpeg_destination_mgr *)jpeg; - - // init compression - - jpeg->cinfo.image_width = width; - jpeg->cinfo.image_height = height; - jpeg->cinfo.input_components = 3; - jpeg->cinfo.in_color_space = JCS_RGB; - - jpeg_set_defaults(&jpeg->cinfo); - jpeg_set_quality(&jpeg->cinfo,quality,TRUE); - - // write tables to SWF - - jpeg_write_tables(&jpeg->cinfo); - - // compess image to SWF - - jpeg_suppress_tables(&jpeg->cinfo, TRUE); - jpeg_start_compress(&jpeg->cinfo, FALSE); - - return (LPJPEGBITS)jpeg; -} - -int SetJPEGBitsLines(LPJPEGBITS jpegbits,U8 ** data,int n) -{ LPJPEGDESTMGR jpeg = (LPJPEGDESTMGR)jpegbits; - if (!jpeg) return -1; - jpeg_write_scanlines(&jpeg->cinfo,data,n); - return 0; -} - -int SetJPEGBitsLine(LPJPEGBITS jpegbits,U8 * data) -{ return SetJPEGBitsLines(jpegbits,&data,1); -} - -int SetJPEGBitsFinish(LPJPEGBITS jpegbits) -{ LPJPEGDESTMGR jpeg = (LPJPEGDESTMGR)jpegbits; - if (!jpeg) return -1; - jpeg_finish_compress(&jpeg->cinfo); - free(jpeg); - return 0; -} - -int SetJPEGBits(LPTAG t,char * fname,int quality) -{ struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - LPJPEGBITS out; - FILE * f; - U8 * scanline; - - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - - if ((f=fopen(fname,"rb"))==NULL) return -1; - - - jpeg_stdio_src(&cinfo,f); - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - - out = SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality); - scanline = (U8*)malloc(4*cinfo.output_width); - - if (scanline) - { int y; - U8 * js = scanline; - for (y=0;y + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#define OUTBUFFER_SIZE 0x8000 + +#ifdef HAVE_JPEGLIB + +typedef struct _JPEGDESTMGR +{ struct jpeg_destination_mgr mgr; + TAG * t; + JOCTET * buffer; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; +} JPEGDESTMGR, * LPJPEGDESTMGR; + +// Destination manager callbacks + +static void RFXSWF_init_destination(j_compress_ptr cinfo) +{ JPEGDESTMGR * dmgr = (JPEGDESTMGR *)cinfo->dest; + dmgr->buffer = (JOCTET*)rfx_alloc(OUTBUFFER_SIZE); + dmgr->mgr.next_output_byte = dmgr->buffer; + dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE; +} + +static boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo) +{ JPEGDESTMGR * dmgr = (JPEGDESTMGR *)cinfo->dest; + swf_SetBlock(dmgr->t,(U8*)dmgr->buffer,OUTBUFFER_SIZE); + dmgr->mgr.next_output_byte = dmgr->buffer; + dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE; + return TRUE; +} + +static void RFXSWF_term_destination(j_compress_ptr cinfo) +{ JPEGDESTMGR * dmgr = (JPEGDESTMGR *)cinfo->dest; + swf_SetBlock(dmgr->t,(U8*)dmgr->buffer,OUTBUFFER_SIZE-dmgr->mgr.free_in_buffer); + rfx_free(dmgr->buffer); + dmgr->mgr.free_in_buffer = 0; +} + +JPEGBITS * swf_SetJPEGBitsStart(TAG * t,int width,int height,int quality) +{ + JPEGDESTMGR * jpeg; + + // redirect compression lib output to local SWF Tag structure + + jpeg = (JPEGDESTMGR *)rfx_calloc(sizeof(JPEGDESTMGR)); + + jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr); + + jpeg_create_compress(&jpeg->cinfo); + + jpeg->mgr.init_destination = RFXSWF_init_destination; + jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer; + jpeg->mgr.term_destination = RFXSWF_term_destination; + + jpeg->t = t; + + jpeg->cinfo.dest = (struct jpeg_destination_mgr *)jpeg; + + // init compression + + jpeg->cinfo.image_width = width; + jpeg->cinfo.image_height = height; + jpeg->cinfo.input_components = 3; + jpeg->cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&jpeg->cinfo); + jpeg_set_quality(&jpeg->cinfo,quality,TRUE); + + // write tables to SWF + + jpeg_write_tables(&jpeg->cinfo); + + // compess image to SWF + + jpeg_suppress_tables(&jpeg->cinfo, TRUE); + jpeg_start_compress(&jpeg->cinfo, FALSE); + + return (JPEGBITS *)jpeg; +} + +int swf_SetJPEGBitsLines(JPEGBITS * jpegbits,U8 ** data,int n) +{ JPEGDESTMGR * jpeg = (JPEGDESTMGR *)jpegbits; + if (!jpeg) return -1; + jpeg_write_scanlines(&jpeg->cinfo,data,n); + return 0; +} + +int swf_SetJPEGBitsLine(JPEGBITS * jpegbits,U8 * data) +{ return swf_SetJPEGBitsLines(jpegbits,&data,1); +} + +int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits) +{ JPEGDESTMGR * jpeg = (JPEGDESTMGR *)jpegbits; + if (!jpeg) return -1; + jpeg_finish_compress(&jpeg->cinfo); + rfx_free(jpeg); + return 0; +} + +void swf_SetJPEGBits2(TAG * tag,U16 width,U16 height,RGBA* bitmap, int quality) +{ + JPEGBITS* jpeg; + int y; + jpeg = swf_SetJPEGBitsStart(tag,width,height,quality); + for (y=0;y=0;x--) { + js[x*3] = js[x*3+1] = js[x*3+2] = js[x]; + } + swf_SetJPEGBitsLines(out,(U8**)&js,1); + } + } + else if(cinfo.out_color_space == JCS_RGB) + { + for (y=0;y>8); + js[x*3+1] = y - ((88*(u-128)+183*(v-128))>>8); + js[x*3+2] = y + ((455 * (u-128))>>8); + } + } + } + else if(cinfo.out_color_space == JCS_CMYK) + { + for (y=0;yRGB conversion routines I found in the + web. (which all produced garbage) + I'm happily accepting suggestions. (mk)*/ + for(x=0;x>8); + js[x*3+1] = white - ((js[x*4+1]*white)>>8); + js[x*3+2] = white - ((js[x*4+2]*white)>>8); + } + swf_SetJPEGBitsLines(out,(U8**)&js,1); + } + } + } + + swf_SetJPEGBitsFinish(out); + jpeg_finish_decompress(&cinfo); + fclose(f); + + return 0; +} + +/* jpeg_source_mgr functions */ +static void tag_init_source(struct jpeg_decompress_struct *cinfo) +{ + TAG*tag = (TAG*)cinfo->client_data; + swf_SetTagPos(tag, 2); + cinfo->src->bytes_in_buffer = 0; +} +static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo) +{ + TAG*tag = (TAG*)cinfo->client_data; + if(tag->data[tag->pos+0] == 0xff && + tag->data[tag->pos+1] == 0xd9 && + tag->data[tag->pos+2] == 0xff && + tag->data[tag->pos+3] == 0xd8) { + tag->pos += 4; + } + if(tag->pos >= tag->len) { + cinfo->src->next_input_byte = 0; + cinfo->src->bytes_in_buffer = 0; + return 0; + } + cinfo->src->next_input_byte = &tag->data[tag->pos]; + cinfo->src->bytes_in_buffer = 1;//tag->len - tag->pos; + tag->pos += 1; + return 1; +} +static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count) +{ + TAG*tag = (TAG*)cinfo->client_data; + cinfo->src->next_input_byte = 0; + cinfo->src->bytes_in_buffer = 0; + tag->pos += count; +} +static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired) +{ + return jpeg_resync_to_restart(cinfo, desired); +} +static void tag_term_source(struct jpeg_decompress_struct *cinfo) +{ + TAG*tag = (TAG*)cinfo->client_data; +} +RGBA* swf_JPEG2TagToImage(TAG*tag, int*width, int*height) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + struct jpeg_source_mgr mgr; + RGBA * dest; + int y; + *width = 0; + *height = 0; + + if(tag->id == ST_DEFINEBITSJPEG) { + fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported"); + return 0; + } + if(tag->id == ST_DEFINEBITSJPEG3) { + fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not yet supported"); + return 0; + } + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + cinfo.client_data = (void*)tag; + cinfo.src = &mgr; + cinfo.src->init_source = tag_init_source; + cinfo.src->fill_input_buffer = tag_fill_input_buffer; + cinfo.src->skip_input_data = tag_skip_input_data; + cinfo.src->resync_to_restart = jpeg_resync_to_restart; + cinfo.src->term_source = tag_term_source; + cinfo.out_color_space = JCS_RGB; + + jpeg_read_header(&cinfo, TRUE); + *width = cinfo.image_width; + *height = cinfo.image_height; + dest = rfx_alloc(sizeof(RGBA)*cinfo.image_width*cinfo.image_height); + + jpeg_start_decompress(&cinfo); + for (y=0;y=0;--x) { + int r = to[x*3+0]; + int g = to[x*3+1]; + int b = to[x*3+2]; + line[x].r = r; + line[x].g = g; + line[x].b = b; + line[x].a = 255; + } + } + + jpeg_finish_decompress(&cinfo); + + jpeg_destroy_decompress(&cinfo); + return dest; +} + + +#endif // HAVE_JPEGLIB + +// Lossless compression texture based on zlib + +#ifdef HAVE_ZLIB + +int RFXSWF_deflate_wraper(TAG * t,z_stream * zs,boolean finish) +{ + U8*data=rfx_alloc(OUTBUFFER_SIZE); + zs->next_out = data; + zs->avail_out = OUTBUFFER_SIZE; + while (1) + { int status = deflate(zs,Z_NO_FLUSH); + + if (status!=Z_OK) + { +#ifdef DEBUG_RFXSWF + fprintf(stderr,"rfxswf: zlib compression error (%i)\n",status); +#endif + rfx_free(data); + return status; + } + + if (zs->next_out!=data) + { swf_SetBlock(t,data,zs->next_out - data); + zs->next_out = data; + zs->avail_out = OUTBUFFER_SIZE; + } + + if (zs->avail_in==0) + break; + } + + if(!finish) { + rfx_free(data); + return 0; + } + + while(1) { + int status = deflate(zs,Z_FINISH); + if (status!=Z_OK && status!=Z_STREAM_END) + { +#ifdef DEBUG_RFXSWF + fprintf(stderr,"rfxswf: zlib compression error (%i)\n",status); +#endif + rfx_free(data); + return status; + } + + if (zs->next_out!=data) + { + swf_SetBlock(t,data,zs->next_out - data); + zs->next_out = data; + zs->avail_out = OUTBUFFER_SIZE; + } + + if(status == Z_STREAM_END) + break; + } + rfx_free(data); + return 0; +} + + +int swf_SetLosslessBits(TAG * t,U16 width,U16 height,void * bitmap,U8 bitmap_flags) +{ int res = 0; + int bps; + + switch (bitmap_flags) + { case BMF_8BIT: + return swf_SetLosslessBitsIndexed(t,width,height,bitmap,NULL,256); + case BMF_16BIT: + bps = BYTES_PER_SCANLINE(sizeof(U16)*width); + break; + case BMF_32BIT: + bps = width*4; + break; + default: + fprintf(stderr, "rfxswf: unknown bitmap type %d\n", bitmap_flags); + return -1; + } + + swf_SetU8(t,bitmap_flags); + swf_SetU16(t,width); + swf_SetU16(t,height); + + { z_stream zs; + + memset(&zs,0x00,sizeof(z_stream)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + + if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK) + { zs.avail_in = bps*height; + zs.next_in = bitmap; + + if (RFXSWF_deflate_wraper(t,&zs,TRUE)<0) res = -3; + deflateEnd(&zs); + + } else res = -3; // zlib error + } + return res; +} + +int swf_SetLosslessBitsIndexed(TAG * t,U16 width,U16 height,U8 * bitmap,RGBA * palette,U16 ncolors) +{ RGBA * pal = palette; + int bps = BYTES_PER_SCANLINE(width); + int res = 0; + + if (!pal) // create default palette for grayscale images + { int i; + pal = rfx_alloc(256*sizeof(RGBA)); + for (i=0;i<256;i++) { pal[i].r = pal[i].g = pal[i].b = i; pal[i].a = 0xff;} + ncolors = 256; + } + + if ((ncolors<2)||(ncolors>256)||(!t)) { + fprintf(stderr, "rfxswf: unsupported number of colors: %d\n", ncolors); + return -1; // parameter error + } + + swf_SetU8(t,BMF_8BIT); + swf_SetU16(t,width); + swf_SetU16(t,height); + swf_SetU8(t,ncolors-1); // number of pal entries + + { z_stream zs; + + memset(&zs,0x00,sizeof(z_stream)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + + if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK) + { U8 * zpal; // compress palette + if ((zpal = rfx_alloc(ncolors*4))) + { U8 * pp = zpal; + int i; + + /* be careful with ST_DEFINEBITSLOSSLESS2, because + the Flash player produces great bugs if you use too many + alpha colors in your palette. The only sensible result that + can be archeived is setting one color to r=0,b=0,g=0,a=0 to + make transparent parts in sprites. That's the cause why alpha + handling is implemented in lossless routines of rfxswf. + + Indeed: I haven't understood yet how flash player handles + alpha values different from 0 and 0xff in lossless bitmaps... + */ + + if (swf_GetTagID(t)==ST_DEFINEBITSLOSSLESS2) // have alpha channel? + { for (i=0;iid == ST_DEFINEBITSLOSSLESS2; + int t,x,y; + RGBA*palette = 0; + U8*data,*data2; + RGBA*dest; + if(tag->id != ST_DEFINEBITSLOSSLESS && + tag->id != ST_DEFINEBITSLOSSLESS2) { + fprintf(stderr, "rfxswf: Object %d is not a PNG picture!\n",GET16(tag->data)); + return 0; + } + swf_SetTagPos(tag, 0); + id =swf_GetU16(tag); + format = swf_GetU8(tag); + if(format == 3) bpp = 8; + if(format == 4) bpp = 16; + if(format == 5) bpp = 32; + if(format!=3 && format!=5) { + if(format==4) + fprintf(stderr, "rfxswf: Can't handle 16-bit palette images yet (image %d)\n",id); + else + fprintf(stderr, "rfxswf: Unknown image type %d in image %d\n", format, id); + return 0; + } + *dwidth = width = swf_GetU16(tag); + *dheight = height = swf_GetU16(tag); + + dest = rfx_alloc(sizeof(RGBA)*width*height); + + if(format == 3) cols = swf_GetU8(tag) + 1; + else cols = 0; + + data = 0; + datalen = (width*height*bpp/8+cols*8); + do { + if(data) + rfx_free(data); + datalen+=4096; + data = rfx_alloc(datalen); + error = uncompress (data, &datalen, &tag->data[tag->pos], tag->len-tag->pos); + } while(error == Z_BUF_ERROR); + if(error != Z_OK) { + fprintf(stderr, "rfxswf: Zlib error %d (image %d)\n", error, id); + return 0; + } + pos = 0; + + if(cols) { + palette = (RGBA*)rfx_alloc(cols*sizeof(RGBA)); + for(t=0;tlen; + swf_SetU32(tag, 0); //placeholder + jpeg = swf_SetJPEGBitsStart(tag,width,height,quality); + for (y=0;ydata[pos], tag->len - pos - 4); + + data=rfx_alloc(OUTBUFFER_SIZE); + memset(&zs,0x00,sizeof(z_stream)); + + if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)!=Z_OK) { + fprintf(stderr, "rfxswf: zlib compression failed"); + return -3; + } + + zs.next_out = data; + zs.avail_out = OUTBUFFER_SIZE; + + for (y=0;yid == ST_DEFINEBITSJPEG || + tag->id == ST_DEFINEBITSJPEG2 || + tag->id == ST_DEFINEBITSJPEG3) { +#ifdef HAVE_JPEGLIB + return swf_JPEG2TagToImage(tag, dwidth, dheight); +#else + fprintf(stderr, "rfxswf: Error: No JPEG library compiled in"); + return 0; +#endif + } + if(tag->id == ST_DEFINEBITSLOSSLESS || + tag->id == ST_DEFINEBITSLOSSLESS2) { +#ifdef HAVE_ZLIB + return swf_DefineLosslessBitsTagToImage(tag, dwidth, dheight); +#else + fprintf(stderr, "rfxswf: Error: No JPEG library compiled in"); + return 0; +#endif + } + fprintf(stderr, "rfxswf: Error: Invalid tag (%d, %s)", tag->id, swf_TagGetName(tag)); + return 0; +} + +#undef OUTBUFFER_SIZE +