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 file is distributed under the GPL, see file COPYING for details
14 #define OUTBUFFER_SIZE 0x8000
16 #ifdef _JPEGLIB_INCLUDED_
18 typedef struct _JPEGDESTMGR
19 { struct jpeg_destination_mgr mgr;
22 struct jpeg_compress_struct cinfo;
23 struct jpeg_error_mgr jerr;
24 } JPEGDESTMGR, * LPJPEGDESTMGR;
26 // Destination manager callbacks
28 void RFXSWF_init_destination(j_compress_ptr cinfo)
29 { JPEGDESTMGR * dmgr = (JPEGDESTMGR *)cinfo->dest;
30 dmgr->buffer = (JOCTET*)malloc(OUTBUFFER_SIZE);
31 dmgr->mgr.next_output_byte = dmgr->buffer;
32 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
35 boolean RFXSWF_empty_output_buffer(j_compress_ptr cinfo)
36 { JPEGDESTMGR * dmgr = (JPEGDESTMGR *)cinfo->dest;
37 swf_SetBlock(dmgr->t,(U8*)dmgr->buffer,OUTBUFFER_SIZE);
38 dmgr->mgr.next_output_byte = dmgr->buffer;
39 dmgr->mgr.free_in_buffer = OUTBUFFER_SIZE;
43 void RFXSWF_term_destination(j_compress_ptr cinfo)
44 { JPEGDESTMGR * dmgr = (JPEGDESTMGR *)cinfo->dest;
45 swf_SetBlock(dmgr->t,(U8*)dmgr->buffer,OUTBUFFER_SIZE-dmgr->mgr.free_in_buffer);
47 dmgr->mgr.free_in_buffer = 0;
50 JPEGBITS * swf_SetJPEGBitsStart(TAG * t,int width,int height,int quality)
54 // redirect compression lib output to local SWF Tag structure
56 jpeg = (JPEGDESTMGR *)malloc(sizeof(JPEGDESTMGR));
57 if (!jpeg) return NULL;
59 memset(jpeg,0x00,sizeof(JPEGDESTMGR));
60 jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
62 jpeg_create_compress(&jpeg->cinfo);
64 jpeg->mgr.init_destination = RFXSWF_init_destination;
65 jpeg->mgr.empty_output_buffer = RFXSWF_empty_output_buffer;
66 jpeg->mgr.term_destination = RFXSWF_term_destination;
70 jpeg->cinfo.dest = (struct jpeg_destination_mgr *)jpeg;
74 jpeg->cinfo.image_width = width;
75 jpeg->cinfo.image_height = height;
76 jpeg->cinfo.input_components = 3;
77 jpeg->cinfo.in_color_space = JCS_RGB;
79 jpeg_set_defaults(&jpeg->cinfo);
80 jpeg_set_quality(&jpeg->cinfo,quality,TRUE);
82 // write tables to SWF
84 jpeg_write_tables(&jpeg->cinfo);
86 // compess image to SWF
88 jpeg_suppress_tables(&jpeg->cinfo, TRUE);
89 jpeg_start_compress(&jpeg->cinfo, FALSE);
91 return (JPEGBITS *)jpeg;
94 int swf_SetJPEGBitsLines(JPEGBITS * jpegbits,U8 ** data,int n)
95 { JPEGDESTMGR * jpeg = (JPEGDESTMGR *)jpegbits;
97 jpeg_write_scanlines(&jpeg->cinfo,data,n);
101 int swf_SetJPEGBitsLine(JPEGBITS * jpegbits,U8 * data)
102 { return swf_SetJPEGBitsLines(jpegbits,&data,1);
105 int swf_SetJPEGBitsFinish(JPEGBITS * jpegbits)
106 { JPEGDESTMGR * jpeg = (JPEGDESTMGR *)jpegbits;
107 if (!jpeg) return -1;
108 jpeg_finish_compress(&jpeg->cinfo);
113 int swf_SetJPEGBits(TAG * t,char * fname,int quality)
114 { struct jpeg_decompress_struct cinfo;
115 struct jpeg_error_mgr jerr;
120 cinfo.err = jpeg_std_error(&jerr);
121 jpeg_create_decompress(&cinfo);
123 if ((f=fopen(fname,"rb"))==NULL) return -1;
125 jpeg_stdio_src(&cinfo,f);
126 jpeg_read_header(&cinfo, TRUE);
127 if(JPEG_LIB_VERSION>=62) /* jpeglib Version 6b is required for grayscale-> color conversion */
128 cinfo.out_color_space = JCS_RGB; //automatically convert grayscale images
129 jpeg_start_decompress(&cinfo);
131 out = swf_SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);
132 scanline = (U8*)malloc(4*cinfo.output_width);
137 if(cinfo.out_color_space == JCS_GRAYSCALE) {
138 /* happens only if JPEG_LIB_VERSION above
139 was too small - let's do the conversion ourselves */
140 for (y=0;y<cinfo.output_height;y++)
142 jpeg_read_scanlines(&cinfo,&js,1);
143 for(x=cinfo.output_width-1;x>=0;x--) {
144 js[x*3] = js[x*3+1] = js[x*3+2] = js[x];
146 swf_SetJPEGBitsLines(out,(U8**)&js,1);
150 for (y=0;y<cinfo.output_height;y++)
151 { jpeg_read_scanlines(&cinfo,&js,1);
152 swf_SetJPEGBitsLines(out,(U8**)&js,1);
157 swf_SetJPEGBitsFinish(out);
158 jpeg_finish_decompress(&cinfo);
164 #endif // _JPEGLIB_INCLUDED_
166 // Lossless compression texture based on zlib
168 #ifdef _ZLIB_INCLUDED_
170 int RFXSWF_deflate_wraper(TAG * t,z_stream * zs,U8 * data,boolean finish)
172 { int status = deflate(zs,Z_SYNC_FLUSH);
174 if (zs->avail_out == 0)
175 { swf_SetBlock(t,data,zs->next_out-data);
177 zs->avail_out = OUTBUFFER_SIZE;
181 { if (finish) deflate(zs,Z_FINISH);
188 fprintf(stderr,"rfxswf: zlib compression error (%i)\n",status);
196 int swf_SetLosslessBits(TAG * t,U16 width,U16 height,void * bitmap,U8 bitmap_flags)
201 switch (bitmap_flags)
203 return swf_SetLosslessBitsIndexed(t,width,height,bitmap,NULL,256);
205 bps = BYTES_PER_SCANLINE(sizeof(U16)*width);
214 swf_SetU8(t,bitmap_flags);
216 swf_SetU16(t,height);
218 if (data=malloc(OUTBUFFER_SIZE))
221 memset(&zs,0x00,sizeof(z_stream));
225 if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK)
226 { zs.avail_in = bps*height;
229 zs.avail_out = OUTBUFFER_SIZE;
231 if (RFXSWF_deflate_wraper(t,&zs,data,TRUE)<0) res = -3;
232 if (zs.next_out>data) swf_SetBlock(t,data,zs.next_out-data);
237 } else res = -3; // zlib error
239 } else res = -2; // memory error
244 int swf_SetLosslessBitsIndexed(TAG * t,U16 width,U16 height,U8 * bitmap,RGBA * palette,U16 ncolors)
245 { RGBA * pal = palette;
246 int bps = BYTES_PER_SCANLINE(width);
250 if (!pal) // create default palette for grayscale images
252 pal = malloc(256*sizeof(RGBA));
253 for (i=0;i<256;i++) { pal[i].r = pal[i].g = pal[i].b = i; pal[i].a = 0xff;}
257 if ((ncolors<2)||(ncolors>256)||(!t)) return -1; // parameter error
259 swf_SetU8(t,BMF_8BIT);
261 swf_SetU16(t,height);
262 swf_SetU8(t,ncolors-1); // number of pal entries
264 if (data=malloc(OUTBUFFER_SIZE))
267 memset(&zs,0x00,sizeof(z_stream));
271 if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK)
272 { U8 * zpal; // compress palette
273 if (zpal = malloc(ncolors*4))
277 /* be careful with ST_DEFINEBITSLOSSLESS2, because
278 the Flash player produces great bugs if you use too many
279 alpha colors in your palette. The only sensible result that
280 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
281 make transparent parts in sprites. That's the cause why alpha
282 handling is implemented in lossless routines of rfxswf.
284 Indeed: I haven't understood yet how flash player handles
285 alpha values different from 0 and 0xff in lossless bitmaps...
288 if (swf_GetTagID(t)==ST_DEFINEBITSLOSSLESS2) // have alpha channel?
289 { for (i=0;i<ncolors;i++)
296 zs.avail_in = 4*ncolors;
299 { for (i=0;i<ncolors;i++) // pack RGBA structures to RGB
305 zs.avail_in = 3*ncolors;
310 zs.avail_out = OUTBUFFER_SIZE;
312 if (RFXSWF_deflate_wraper(t,&zs,data,FALSE)<0) res = -3;
316 zs.avail_in = (bps*height*sizeof(U8));
318 if (RFXSWF_deflate_wraper(t,&zs,data,TRUE)<0) res = -3;
322 if (zs.next_out>data) swf_SetBlock(t,data,zs.next_out-data);
325 } else res = -2; // memory error
326 } else res = -3; // zlib error
330 if (!palette) free(pal);
335 int swf_SetLosslessBitsGrayscale(TAG * t,U16 width,U16 height,U8 * bitmap)
336 { return swf_SetLosslessBitsIndexed(t,width,height,bitmap,NULL,256);
340 #endif // _ZLIB_INCLUDED_
342 #undef OUTBUFFER_SIZE