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 jpeg_start_decompress(&cinfo);
129 out = swf_SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);
130 scanline = (U8*)malloc(4*cinfo.output_width);
135 if(cinfo.out_color_space == JCS_GRAYSCALE) {
136 for (y=0;y<cinfo.output_height;y++)
138 jpeg_read_scanlines(&cinfo,&js,1);
139 for(x=cinfo.output_width-1;x>=0;x--) {
140 js[x*3] = js[x*3+1] = js[x*3+2] = js[x];
142 swf_SetJPEGBitsLines(out,(U8**)&js,1);
145 else if(cinfo.out_color_space == JCS_RGB)
147 for (y=0;y<cinfo.output_height;y++)
148 { jpeg_read_scanlines(&cinfo,&js,1);
149 swf_SetJPEGBitsLines(out,(U8**)&js,1);
152 else if(cinfo.out_color_space == JCS_YCCK)
155 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
158 else if(cinfo.out_color_space == JCS_YCbCr)
160 for (y=0;y<cinfo.output_height;y++) {
162 for(x=0;x<cinfo.output_width;x++) {
167 js[x*3+0] = y + ((360*(v-128))>>8);
168 js[x*3+1] = y - ((88*(u-128)-183*(v-128))>>8);
169 js[x*3+2] = y + ((455 * (u-128))>>8);
173 else if(cinfo.out_color_space == JCS_CMYK)
175 for (y=0;y<cinfo.output_height;y++)
177 jpeg_read_scanlines(&cinfo,&js,1);
178 /* This routine seems to work for now-
179 It's a mixture of 3 different
180 CMYK->RGB conversion routines I found in the
181 web. (which all produced garbage)
182 I'm happily accepting suggestions. (mk)*/
183 for(x=0;x<cinfo.output_width;x++) {
184 int white = 255 - js[x*4+3];
185 js[x*3+0] = white - ((js[x*4]*white)>>8);
186 js[x*3+1] = white - ((js[x*4+1]*white)>>8);
187 js[x*3+2] = white - ((js[x*4+2]*white)>>8);
189 swf_SetJPEGBitsLines(out,(U8**)&js,1);
194 swf_SetJPEGBitsFinish(out);
195 jpeg_finish_decompress(&cinfo);
201 #endif // _JPEGLIB_INCLUDED_
203 // Lossless compression texture based on zlib
205 #ifdef _ZLIB_INCLUDED_
207 int RFXSWF_deflate_wraper(TAG * t,z_stream * zs,U8 * data,boolean finish)
209 { int status = deflate(zs,Z_SYNC_FLUSH);
211 if (zs->avail_out == 0)
212 { swf_SetBlock(t,data,zs->next_out-data);
214 zs->avail_out = OUTBUFFER_SIZE;
218 { if (finish) deflate(zs,Z_FINISH);
225 fprintf(stderr,"rfxswf: zlib compression error (%i)\n",status);
233 int swf_SetLosslessBits(TAG * t,U16 width,U16 height,void * bitmap,U8 bitmap_flags)
238 switch (bitmap_flags)
240 return swf_SetLosslessBitsIndexed(t,width,height,bitmap,NULL,256);
242 bps = BYTES_PER_SCANLINE(sizeof(U16)*width);
251 swf_SetU8(t,bitmap_flags);
253 swf_SetU16(t,height);
255 if (data=malloc(OUTBUFFER_SIZE))
258 memset(&zs,0x00,sizeof(z_stream));
262 if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK)
263 { zs.avail_in = bps*height;
266 zs.avail_out = OUTBUFFER_SIZE;
268 if (RFXSWF_deflate_wraper(t,&zs,data,TRUE)<0) res = -3;
269 if (zs.next_out>data) swf_SetBlock(t,data,zs.next_out-data);
274 } else res = -3; // zlib error
276 } else res = -2; // memory error
281 int swf_SetLosslessBitsIndexed(TAG * t,U16 width,U16 height,U8 * bitmap,RGBA * palette,U16 ncolors)
282 { RGBA * pal = palette;
283 int bps = BYTES_PER_SCANLINE(width);
287 if (!pal) // create default palette for grayscale images
289 pal = malloc(256*sizeof(RGBA));
290 for (i=0;i<256;i++) { pal[i].r = pal[i].g = pal[i].b = i; pal[i].a = 0xff;}
294 if ((ncolors<2)||(ncolors>256)||(!t)) return -1; // parameter error
296 swf_SetU8(t,BMF_8BIT);
298 swf_SetU16(t,height);
299 swf_SetU8(t,ncolors-1); // number of pal entries
301 if (data=malloc(OUTBUFFER_SIZE))
304 memset(&zs,0x00,sizeof(z_stream));
308 if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK)
309 { U8 * zpal; // compress palette
310 if (zpal = malloc(ncolors*4))
314 /* be careful with ST_DEFINEBITSLOSSLESS2, because
315 the Flash player produces great bugs if you use too many
316 alpha colors in your palette. The only sensible result that
317 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
318 make transparent parts in sprites. That's the cause why alpha
319 handling is implemented in lossless routines of rfxswf.
321 Indeed: I haven't understood yet how flash player handles
322 alpha values different from 0 and 0xff in lossless bitmaps...
325 if (swf_GetTagID(t)==ST_DEFINEBITSLOSSLESS2) // have alpha channel?
326 { for (i=0;i<ncolors;i++)
333 zs.avail_in = 4*ncolors;
336 { for (i=0;i<ncolors;i++) // pack RGBA structures to RGB
342 zs.avail_in = 3*ncolors;
347 zs.avail_out = OUTBUFFER_SIZE;
349 if (RFXSWF_deflate_wraper(t,&zs,data,FALSE)<0) res = -3;
353 zs.avail_in = (bps*height*sizeof(U8));
355 if (RFXSWF_deflate_wraper(t,&zs,data,TRUE)<0) res = -3;
359 if (zs.next_out>data) swf_SetBlock(t,data,zs.next_out-data);
362 } else res = -2; // memory error
363 } else res = -3; // zlib error
367 if (!palette) free(pal);
372 int swf_SetLosslessBitsGrayscale(TAG * t,U16 width,U16 height,U8 * bitmap)
373 { return swf_SetLosslessBitsIndexed(t,width,height,bitmap,NULL,256);
377 #endif // _ZLIB_INCLUDED_
379 #undef OUTBUFFER_SIZE