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
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 void swf_SetJPEGBits2(TAG * tag,U16 width,U16 height,RGBA* bitmap, int quality)
117 jpeg = swf_SetJPEGBitsStart(tag,width,height,quality);
118 for (y=0;y<height;y++)
119 { U8 scanline[3*width];
121 for (x=0;x<width;x++)
122 { scanline[p++] = bitmap[width*y+x].r;
123 scanline[p++] = bitmap[width*y+x].g;
124 scanline[p++] = bitmap[width*y+x].b;
126 swf_SetJPEGBitsLine(jpeg,scanline);
128 swf_SetJPEGBitsFinish(jpeg);
131 int swf_SetJPEGBits(TAG * t,char * fname,int quality)
132 { struct jpeg_decompress_struct cinfo;
133 struct jpeg_error_mgr jerr;
138 cinfo.err = jpeg_std_error(&jerr);
139 jpeg_create_decompress(&cinfo);
141 if ((f=fopen(fname,"rb"))==NULL) return -1;
143 jpeg_stdio_src(&cinfo,f);
144 jpeg_read_header(&cinfo, TRUE);
145 jpeg_start_decompress(&cinfo);
147 out = swf_SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);
148 scanline = (U8*)malloc(4*cinfo.output_width);
153 if(cinfo.out_color_space == JCS_GRAYSCALE) {
154 for (y=0;y<cinfo.output_height;y++)
156 jpeg_read_scanlines(&cinfo,&js,1);
157 for(x=cinfo.output_width-1;x>=0;x--) {
158 js[x*3] = js[x*3+1] = js[x*3+2] = js[x];
160 swf_SetJPEGBitsLines(out,(U8**)&js,1);
163 else if(cinfo.out_color_space == JCS_RGB)
165 for (y=0;y<cinfo.output_height;y++)
166 { jpeg_read_scanlines(&cinfo,&js,1);
167 swf_SetJPEGBitsLines(out,(U8**)&js,1);
170 else if(cinfo.out_color_space == JCS_YCCK)
173 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
176 else if(cinfo.out_color_space == JCS_YCbCr)
178 for (y=0;y<cinfo.output_height;y++) {
180 for(x=0;x<cinfo.output_width;x++) {
185 js[x*3+0] = y + ((360*(v-128))>>8);
186 js[x*3+1] = y - ((88*(u-128)-183*(v-128))>>8);
187 js[x*3+2] = y + ((455 * (u-128))>>8);
191 else if(cinfo.out_color_space == JCS_CMYK)
193 for (y=0;y<cinfo.output_height;y++)
195 jpeg_read_scanlines(&cinfo,&js,1);
196 /* This routine seems to work for now-
197 It's a mixture of 3 different
198 CMYK->RGB conversion routines I found in the
199 web. (which all produced garbage)
200 I'm happily accepting suggestions. (mk)*/
201 for(x=0;x<cinfo.output_width;x++) {
202 int white = 255 - js[x*4+3];
203 js[x*3+0] = white - ((js[x*4]*white)>>8);
204 js[x*3+1] = white - ((js[x*4+1]*white)>>8);
205 js[x*3+2] = white - ((js[x*4+2]*white)>>8);
207 swf_SetJPEGBitsLines(out,(U8**)&js,1);
212 swf_SetJPEGBitsFinish(out);
213 jpeg_finish_decompress(&cinfo);
219 #endif // HAVE_JPEGLIB
221 // Lossless compression texture based on zlib
225 int RFXSWF_deflate_wraper(TAG * t,z_stream * zs,U8 * data,boolean finish)
227 { int status = deflate(zs,Z_SYNC_FLUSH);
229 if (zs->avail_out == 0)
230 { swf_SetBlock(t,data,zs->next_out-data);
232 zs->avail_out = OUTBUFFER_SIZE;
236 { if (finish) deflate(zs,Z_FINISH);
243 fprintf(stderr,"rfxswf: zlib compression error (%i)\n",status);
252 int swf_SetLosslessBits(TAG * t,U16 width,U16 height,void * bitmap,U8 bitmap_flags)
257 switch (bitmap_flags)
259 return swf_SetLosslessBitsIndexed(t,width,height,bitmap,NULL,256);
261 bps = BYTES_PER_SCANLINE(sizeof(U16)*width);
270 swf_SetU8(t,bitmap_flags);
272 swf_SetU16(t,height);
274 if ((data=malloc(OUTBUFFER_SIZE)))
277 memset(&zs,0x00,sizeof(z_stream));
281 if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK)
282 { zs.avail_in = bps*height;
285 zs.avail_out = OUTBUFFER_SIZE;
287 if (RFXSWF_deflate_wraper(t,&zs,data,TRUE)<0) res = -3;
288 if (zs.next_out>data) swf_SetBlock(t,data,zs.next_out-data);
292 } else res = -3; // zlib error
294 } else res = -2; // memory error
299 int swf_SetLosslessBitsIndexed(TAG * t,U16 width,U16 height,U8 * bitmap,RGBA * palette,U16 ncolors)
300 { RGBA * pal = palette;
301 int bps = BYTES_PER_SCANLINE(width);
305 if (!pal) // create default palette for grayscale images
307 pal = malloc(256*sizeof(RGBA));
308 for (i=0;i<256;i++) { pal[i].r = pal[i].g = pal[i].b = i; pal[i].a = 0xff;}
312 if ((ncolors<2)||(ncolors>256)||(!t)) return -1; // parameter error
314 swf_SetU8(t,BMF_8BIT);
316 swf_SetU16(t,height);
317 swf_SetU8(t,ncolors-1); // number of pal entries
319 if ((data=malloc(OUTBUFFER_SIZE)))
322 memset(&zs,0x00,sizeof(z_stream));
326 if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)==Z_OK)
327 { U8 * zpal; // compress palette
328 if ((zpal = malloc(ncolors*4)))
332 /* be careful with ST_DEFINEBITSLOSSLESS2, because
333 the Flash player produces great bugs if you use too many
334 alpha colors in your palette. The only sensible result that
335 can be archeived is setting one color to r=0,b=0,g=0,a=0 to
336 make transparent parts in sprites. That's the cause why alpha
337 handling is implemented in lossless routines of rfxswf.
339 Indeed: I haven't understood yet how flash player handles
340 alpha values different from 0 and 0xff in lossless bitmaps...
343 if (swf_GetTagID(t)==ST_DEFINEBITSLOSSLESS2) // have alpha channel?
344 { for (i=0;i<ncolors;i++)
351 zs.avail_in = 4*ncolors;
354 { for (i=0;i<ncolors;i++) // pack RGBA structures to RGB
360 zs.avail_in = 3*ncolors;
365 zs.avail_out = OUTBUFFER_SIZE;
367 if (RFXSWF_deflate_wraper(t,&zs,data,FALSE)<0) res = -3;
371 zs.avail_in = (bps*height*sizeof(U8));
373 if (RFXSWF_deflate_wraper(t,&zs,data,TRUE)<0) res = -3;
377 if (zs.next_out>data) swf_SetBlock(t,data,zs.next_out-data);
380 } else res = -2; // memory error
381 } else res = -3; // zlib error
385 if (!palette) free(pal);
390 int swf_SetLosslessBitsGrayscale(TAG * t,U16 width,U16 height,U8 * bitmap)
391 { return swf_SetLosslessBitsIndexed(t,width,height,bitmap,NULL,256);
397 #if defined(HAVE_ZLIB) && defined(HAVE_JPEGLIB)
398 int swf_SetJPEGBits3(TAG * tag,U16 width,U16 height,RGBA* bitmap, int quality)
408 swf_SetU32(tag, 0); //placeholder
409 jpeg = swf_SetJPEGBitsStart(tag,width,height,quality);
410 for (y=0;y<height;y++)
411 { U8 scanline[3*width];
413 for (x=0;x<width;x++)
414 { scanline[p++] = bitmap[width*y+x].r;
415 scanline[p++] = bitmap[width*y+x].g;
416 scanline[p++] = bitmap[width*y+x].b;
418 swf_SetJPEGBitsLine(jpeg,scanline);
420 swf_SetJPEGBitsFinish(jpeg);
421 PUT32(&tag->data[pos], tag->len - pos - 4);
423 data=malloc(OUTBUFFER_SIZE);
424 memset(&zs,0x00,sizeof(z_stream));
426 if (deflateInit(&zs,Z_DEFAULT_COMPRESSION)!=Z_OK) {
427 fprintf(stderr, "rfxswf: zlib compression failed");
432 zs.avail_out = OUTBUFFER_SIZE;
434 for (y=0;y<height;y++)
435 { U8 scanline[width];
437 for (x=0;x<width;x++) {
438 scanline[p++] = bitmap[width*y+x].a;
441 zs.next_in = scanline;
444 if(deflate(&zs, Z_NO_FLUSH) != Z_OK) {
445 fprintf(stderr, "rfxswf: zlib compression failed");
448 if(zs.next_out != data) {
449 swf_SetBlock(tag, data, zs.next_out - data);
451 zs.avail_out = OUTBUFFER_SIZE;
460 int ret = deflate(&zs, Z_FINISH);
462 ret != Z_STREAM_END) {
463 fprintf(stderr, "rfxswf: zlib compression failed");
466 if(zs.next_out != data) {
467 swf_SetBlock(tag, data, zs.next_out - data);
469 zs.avail_out = OUTBUFFER_SIZE;
471 if (ret == Z_STREAM_END) {
482 #undef OUTBUFFER_SIZE