1 /* libsswf_tag_image.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */
2 
3 /*
4 
5 Copyright (c) 2002-2008 Made to Order Software Corp.
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 /** \file
35  *
36  * \brief The implementation of the sswf::TagImage class
37  *
38  * This file declares the body of the functions which are not
39  * inline. It is part of the SSWF library.
40  */
41 
42 #include	"sswf/libsswf.h"
43 
44 using namespace sswf;
45 
46 
47 
48 
49 /////////////////////////////////////////// TagImage
50 
51 
52 /** \class sswf::TagImage
53  *
54  * \brief The image class in SWF.
55  *
56  * This class is used to include an image in an SWF animation.
57  * Images become fills in a style which is then rendered by a
58  * shape object.
59  *
60  * SWF supports only two image formats: JPEG and Lossless (which
61  * is similar to PNG: a compressed bitmap using zlib.)
62  *
63  * Older movies were constrained to one set of JPEG Tables and any
64  * number of DefineBitsJPEG. Newer movies can incorporate the JPEG
65  * Tables in the DefineBitsJPEG2. Also, since version 3, SWF supports
66  * DefineBitsJPEG3 that includes an alpha channel (compressed with
67  * zlib) for JPEG images.
68  *
69  * Lossless images can also include an alpha channel. It supports
70  * different formats such as grey scales and paletted images.
71  * The library will automatically try to use a palette if possible
72  * (i.e. if your image is small or only uses a very limited number
73  * of colors.)
74  *
75  * \sa <a href="../SWFalexref.html#tag_jpegtables">SWF Alexis' Reference&mdash;DefineJPEGTables</a>
76  * \sa <a href="../SWFalexref.html#tag_definebitsjpeg">SWF Alexis' Reference&mdash;DefineBitsJPEG</a>
77  * \sa <a href="../SWFalexref.html#tag_definebitsjpeg2">SWF Alexis' Reference&mdash;DefineBitsJPEG2</a>
78  * \sa <a href="../SWFalexref.html#tag_definebitsjpeg3">SWF Alexis' Reference&mdash;DefineBitsJPEG3</a>
79  * \sa <a href="../SWFalexref.html#tag_definebitslossless">SWF Alexis' Reference&mdash;DefineBitsLossless</a>
80  * \sa <a href="../SWFalexref.html#tag_definebitslossless2">SWF Alexis' Reference&mdash;DefineBitsLossless2</a>
81  * \sa <a href="../SWFalexref.html#swf_tag">SWF Alexis' Reference&mdash;swf_tag</a>
82  */
83 
84 
85 
86 /** \enum sswf::TagImage::image_format_t
87  *
88  * \brief The list of formats available for the TagImage
89  *
90  * This enumeration lists all the possible formats supported
91  * by the SWF format. Note that does not define the image
92  * formats supported by the SSWF library.
93  */
94 
95 /** \var sswf::TagImage::IMAGE_FORMAT_UNKNOWN
96  *
97  * \brief By default the format of an image is set to Unknown
98  *
99  * This is the default format until you specifically call
100  * the sswf::TagImage::SetFormat() function.
101  *
102  * The TagImage does not try to guess the output format for
103  * you (at least, not yet.)
104  */
105 
106 /** \var sswf::TagImage::IMAGE_FORMAT_LOSSLESS_BEST
107  *
108  * \brief Used to let the library select between the different lossless formats
109  *
110  * This format is a special internal format one can use to let the
111  * library choose between the different available lossless formats.
112  * This means the library will try all the different modes and
113  * choose the one which generates the smallest result.
114  *
115  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_8
116  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_16
117  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_32
118  */
119 
120 /** \var sswf::TagImage::IMAGE_FORMAT_LOSSLESS_8
121  *
122  * \brief Save a paletted image
123  *
124  * This format is not currently supported because we do not have a
125  * working quantization function.
126  *
127  * The sswf::TagImage::IMAGE_FORMAT_LOSSLESS_BEST may make use of
128  * that format if it can transform the entire image to a paletted
129  * image.
130  *
131  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_BEST
132  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_16
133  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_32
134  */
135 
136 /** \var sswf::TagImage::IMAGE_FORMAT_LOSSLESS_16
137  *
138  * \brief Save a lossless image in 16 bits
139  *
140  * Save the image in a lossless 16 bits image. When the
141  * sswf::TagImage::IMAGE_FORMAT_LOSSLESS_BEST is used, it
142  * switches to the 16 bits format only if all the colors
143  * use only the 5 top bits (i.e. bits 0, 1 and 2 are all
144  * zeroes.)
145  *
146  * The 16 bits image is really only 15 bits, 5 bits per
147  * component (xrrrrrgggggbbbbb).
148  *
149  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_BEST
150  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_8
151  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_32
152  */
153 
154 /** \var sswf::TagImage::IMAGE_FORMAT_LOSSLESS_32
155  *
156  * \brief Saves the Lossless image in 32 bits
157  *
158  * This format saves an RGB image in XRGB format and
159  * an ARGB image in ARGB format. When no alpha is saved
160  * it puts 0 everywhere.
161  *
162  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_BEST
163  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_8
164  * \sa sswf::TagImage::IMAGE_FORMAT_LOSSLESS_16
165  */
166 
167 /** \var sswf::TagImage::IMAGE_FORMAT_JPEG
168  *
169  * \brief Saves the image compressed with JPEG
170  *
171  * This format requests that the TagImage be compressed
172  * using the JPEG format.
173  */
174 
175 /** \var sswf::TagImage::IMAGE_FORMAT_max
176  *
177  * \brief Maximum format number.
178  *
179  * This definition is only to define the largest possible
180  * format.
181  */
182 
183 
184 
185 /** \brief Initializes the TagImage object.
186  *
187  * This function initializes the image to all defaults.
188  *
189  * This means no image, no alpha channel, default quality.
190  *
191  * \param[in] parent The TagHeader in which this TagImage is to be inserted
192  */
TagImage(TagBase * parent)193 TagImage::TagImage(TagBase *parent)
194 	: TagBaseID("image", parent)
195 {
196 	f_format = IMAGE_FORMAT_UNKNOWN;
197 	f_image.f_width = 0;
198 	f_image.f_height = 0;
199 	f_image.f_alpha = false;
200 	f_image.f_data = 0;
201 	f_quality = 0;
202 	f_count = 0;
203 	f_colormap = 0;
204 }
205 
206 
207 /* Ensures that the image data buffer is freed
208 TagImage::~TagImage()
209 {
210 	// This is automatic as long as the user uses TagImage::MemAlloc() to
211 	// allocate the buffer.
212 	//MemFree(f_image.f_data);
213 }
214 */
215 
216 
217 /** \fn sswf::TagImage::GetImageData(image_t& image_data)
218  *
219  * \brief Retrieve the current image information.
220  *
221  * This function retrieves the image information. This is a direct
222  * copy of the image structure with the internal data pointer.
223  * Do not modify the pointer or free it.
224  *
225  * \param[out] image_data An image structure
226  *
227  * \return A copy of the internal image structure
228  */
229 
230 
231 /** \fn sswf::TagImage::SetFormat(image_format_t format)
232  *
233  * \brief Set the required format for when the image is to be saved.
234  *
235  * This function setst the format that the TagImage will use when
236  * saving the image.
237  *
238  * The possible formats are:
239  *
240  * \code
241  *	IMAGE_FORMAT_LOSSLESS_BEST
242  *	IMAGE_FORMAT_LOSSLESS_8
243  *	IMAGE_FORMAT_LOSSLESS_16
244  *	IMAGE_FORMAT_LOSSLESS_32
245  *	IMAGE_FORMAT_JPEG
246  * \endcode
247  *
248  * The IMAGE_FORMAT_LOSSLESS_BEST format is used to let the system
249  * choose between the different LOSSLESS formats. It is lossless
250  * meaning that the best to ensure the smallest possible image
251  * is used without losing even one pixel (which often means using
252  * LOSSLESS 32.)
253  *
254  * \param[in] format One of the IMAGE_FORMAT_...
255  */
256 
257 
258 /** \fn sswf::TagImage::SetQuality(int quality)
259  *
260  * \brief Defines the quality level for a JPEG.
261  *
262  * When saving an image using the JPEG format, one can choose the
263  * quality of the image. This is done with this function.
264  *
265  * The quality is a number from 0 to 100.
266  *
267  * \param[in] quality	The quality used to compress the image to a JPEG
268  */
269 
270 
271 /** \brief Returns the flags defined for a TagImage.
272  *
273  * This function defines the type flags for a tag image.
274  *
275  * It is a definition and it has an identifier.
276  *
277  * \return SWF_TYPE_DEFINE and SWF_TYPE_HAS_ID
278  */
TypeFlags(void) const279 TagBase::swf_type_t TagImage::TypeFlags(void) const
280 {
281 	return SWF_TYPE_DEFINE | SWF_TYPE_HAS_ID;
282 }
283 
284 
285 
286 
287 /// The offsets to read/write in the header of a targa image file
288 enum targa_header_t {
289 	TGA_OFFSET_IDENTIFIER_LENGTH = 0,
290 	TGA_OFFSET_COLORMAP_TYPE,
291 	TGA_OFFSET_IMAGE_TYPE,			// includes compression flag
292 	TGA_OFFSET_COLORMAP_INDEX_LO,
293 	TGA_OFFSET_COLORMAP_INDEX_HI,
294 	TGA_OFFSET_COLORMAP_LENGTH_LO,
295 	TGA_OFFSET_COLORMAP_LENGTH_HI,
296 	TGA_OFFSET_COLORMAP_SIZE,
297 	TGA_OFFSET_ORIGIN_X_LO,
298 	TGA_OFFSET_ORIGIN_X_HI,
299 	TGA_OFFSET_ORIGIN_Y_LO,
300 	TGA_OFFSET_ORIGIN_Y_HI,
301 	TGA_OFFSET_WIDTH_LO,
302 	TGA_OFFSET_WIDTH_HI,
303 	TGA_OFFSET_HEIGHT_LO,
304 	TGA_OFFSET_HEIGHT_HI,
305 	TGA_OFFSET_BITS_PER_PIXEL,
306 	TGA_OFFSET_FLAGS,
307 
308 	TGA_HEADER_SIZE			// the size of the targa files header
309 };
310 
311 
312 
313 
314 //********************************************************************************
315 //**********   JPEG Loader/Saver   ***********************************************
316 //********************************************************************************
317 // this is really ugly and hopefully it will change one day!
318 extern "C" {
319 // NOTE: in older versions, the JPEG includes didn't support C++
320 #include	<jpeglib.h>
321 #include	<jerror.h>
322 #include	<setjmp.h>
323 
324 /// Structure used to read a JPG image
325 typedef struct SSWF_JPG_ERROR {
326 	struct jpeg_error_mgr	pub;		/* "public" fields of the error manager */
327 	jmp_buf			setjmp_buffer;	/* for return to caller */
328 } sswf_jpg_error;
329 
330 #define	SSWF_JPG_BUFSIZE		4096
331 
332 
333 /// Structure definition for the source buffer of a JPG image
334 typedef struct SSWF_JPG_SOURCE {
335 	struct jpeg_source_mgr	src;
336 	FILE *			file;
337 	JOCTET			buffer[SSWF_JPG_BUFSIZE];		/* temporary data */
338 } sswf_jpg_source;
339 
340 #define	jsrc	((sswf_jpg_source *) cinfo->src)
341 
342 
343 
344 /// Structure definition for the destination buffer of a JPG image
345 typedef struct SSWF_JPG_DESTINATION {
346 	struct jpeg_destination_mgr	dst;
347 	Data *				encoding;
348 	Data *				image;
349 	Data *				current;
350 	unsigned long			size;
351 	unsigned long			offset;
352 	long				state;
353 	long				last_code;		/* 0xFF 0x?? - the 0x?? value */
354 	JOCTET				buffer[SSWF_JPG_BUFSIZE];
355 } sswf_jpg_destination;
356 
357 #define	jdst	((sswf_jpg_destination *) cinfo->dest)
358 
359 
360 
361 /* if an error occurs, this function will be called and the JPEG process will be stopped */
sswfJPEGError(j_common_ptr cinfo)362 static void sswfJPEGError(j_common_ptr cinfo)
363 {
364 	sswf_jpg_error	*myerr;
365 
366 	myerr = (sswf_jpg_error *) cinfo->err;	/* cinfo->err really points to a img_jpg_error struct, so coerce pointer */
367 	longjmp(myerr->setjmp_buffer, 1);	/* Return control to the setjmp point */
368 /*NOTREACHED*/
369 }
370 
371 
372 
373 
sswfFillInputBuffer(j_decompress_ptr cinfo)374 static boolean sswfFillInputBuffer(j_decompress_ptr cinfo)
375 {
376 	int		r;
377 
378 	jsrc->src.next_input_byte = jsrc->buffer;
379 	r = fread(jsrc->buffer, 1, SSWF_JPG_BUFSIZE, jsrc->file);
380 	if(r < 0) {
381 		return FALSE;
382 	}
383 	else if(r == 0) {
384 		/* send an "end of image" - i.e. EOF... */
385 		jsrc->buffer[0] = JPEG_EOI;
386 		r = 1;
387 	}
388 	jsrc->src.bytes_in_buffer = r;
389 
390 	return TRUE;
391 }
392 
393 
sswfInitSource(j_decompress_ptr cinfo)394 static void sswfInitSource(j_decompress_ptr cinfo)
395 {
396 	(void) sswfFillInputBuffer(cinfo);
397 }
398 
399 
sswfSkipInputData(j_decompress_ptr cinfo,long num_bytes)400 static void sswfSkipInputData(j_decompress_ptr cinfo, long num_bytes)
401 {
402 	int		r;
403 
404 	if(num_bytes > 0) {
405 		r = jsrc->src.bytes_in_buffer;
406 		r -= num_bytes;
407 		if(r > 0) {
408 			jsrc->src.next_input_byte += num_bytes;
409 			jsrc->src.bytes_in_buffer = r;
410 		}
411 		else {
412 			if(r < 0) {
413 				// skip these bytes and read in some more data
414 				fseek(jsrc->file, -r, SEEK_CUR);
415 			}
416 			(void) sswfFillInputBuffer(cinfo);
417 		}
418 	}
419 }
420 
421 
sswfResyncToRestart(j_decompress_ptr cinfo,int desired)422 static boolean sswfResyncToRestart(j_decompress_ptr cinfo, int desired)
423 {
424 	return jpeg_resync_to_restart(cinfo, desired);
425 }
426 
427 
sswfTermSource(j_decompress_ptr cinfo)428 static void sswfTermSource(j_decompress_ptr cinfo)
429 {
430 }
431 
432 
433 
434 
435 
436 
sswfWriteData(sswf_jpg_destination * dst,const unsigned char * buffer,unsigned long size)437 static void sswfWriteData(sswf_jpg_destination *dst, const unsigned char *buffer, unsigned long size)
438 {
439 	while(size > 0) {
440 		switch(dst->state) {
441 		case 0:
442 			/* we expect 0xFF */
443 			if(*buffer != 0xFF) {
444 				fflush(stdout);
445 				fprintf(stderr, "WARNING: at offset %ld the JPEG format didn't send us 0xFF when expected! (Got 0x%02X instead)\n", dst->offset, (int) *buffer);
446 			}
447 			else {
448 				dst->state = 1;
449 			}
450 			buffer++;
451 			size--;
452 			dst->offset++;
453 			break;
454 
455 		case 1:
456 			/* we expect a valid JPEG code - though this isn't tested...
457 			 * we just catch a few codes we need to know of in order to
458 			 * insert the extra bytes we need there
459 			 */
460 			dst->last_code = *buffer;
461 			buffer++;
462 			size--;
463 			dst->offset++;
464 			switch(dst->last_code) {
465 			case 0xD8:		// start -> empty tag
466 				dst->image->PutByte((unsigned char) 0xFF);
467 				dst->image->PutByte((unsigned char) 0xD8);
468 				dst->encoding->PutByte((unsigned char) 0xFF);
469 				dst->encoding->PutByte((unsigned char) 0xD8);
470 				dst->state = 0;
471 				break;
472 
473 			case 0xD9:		// end -> empty tag
474 				assert(0, "at offset %ld in the JPEG format, we didn't expect the end marker (0xFF 0xD9)\n", dst->offset);
475 				/*NOTREACHED*/
476 
477 			case 0xDA:
478 				/* switch to image data only now */
479 				// encoding is over
480 				dst->encoding->PutByte((unsigned char) 0xFF);
481 				dst->encoding->PutByte((unsigned char) 0xD9);
482 
483 				// we need the 0xFF 0xDA still in the other buffer
484 				dst->image->PutByte((unsigned char) 0xFF);
485 				dst->image->PutByte((unsigned char) 0xDA);
486 				dst->state = 5;
487 				break;
488 
489 			// not sure which tags are supposed to be in the 1st and 2nd streams...
490 			case 0xE0:
491 			case 0xC0:
492 				dst->current = dst->image;
493 				dst->state = 2;
494 				break;
495 
496 			default:
497 				dst->current = dst->encoding;
498 				dst->state = 2;
499 				break;
500 
501 			}
502 			break;
503 
504 		case 2:
505 			/* get 1st byte of size */
506 			dst->size = *buffer * 256;
507 			dst->state = 3;
508 			buffer++;
509 			size--;
510 			dst->offset++;
511 			break;
512 
513 		case 3:
514 			dst->size += *buffer;
515 			buffer++;
516 			size--;
517 			dst->offset++;
518 
519 			/* can the size be zero here?!? */
520 			if(dst->size > 0) {
521 				dst->current->PutByte((unsigned char) 0xFF);
522 				dst->current->PutByte((unsigned char) dst->last_code);
523 				dst->current->PutByte((unsigned char) (dst->size >> 8));
524 				dst->current->PutByte((unsigned char) dst->size);
525 
526 				dst->size -= 2;
527 
528 				dst->state = 4;
529 			}
530 			else {
531 				dst->state = 0;
532 			}
533 			break;
534 
535 		case 4:
536 			if(size >= dst->size) {
537 				dst->current->Write(buffer, dst->size);
538 				buffer += dst->size;
539 				size -= dst->size;
540 				dst->offset += dst->size;
541 				dst->state = 0;
542 			}
543 			else {
544 				dst->current->Write(buffer, size);
545 				dst->offset += size;
546 				size = 0;		/* buffer used up */
547 			}
548 			break;
549 
550 		case 5:
551 			dst->image->Write(buffer, size);
552 			size = 0;
553 			break;
554 
555 		}
556 	}
557 }
558 
559 
sswfInitDestination(j_compress_ptr cinfo)560 static void sswfInitDestination(j_compress_ptr cinfo)
561 {
562 	jdst->dst.next_output_byte = jdst->buffer;
563 	jdst->dst.free_in_buffer = SSWF_JPG_BUFSIZE;
564 }
565 
566 
sswfEmptyOutputBuffer(j_compress_ptr cinfo)567 static boolean sswfEmptyOutputBuffer(j_compress_ptr cinfo)
568 {
569 	sswfWriteData(jdst, jdst->buffer, SSWF_JPG_BUFSIZE);
570 	jdst->dst.next_output_byte = jdst->buffer;
571 	jdst->dst.free_in_buffer = SSWF_JPG_BUFSIZE;
572 
573 	return TRUE;
574 }
575 
576 
sswfTermDestination(j_compress_ptr cinfo)577 static void sswfTermDestination(j_compress_ptr cinfo)
578 {
579 	int		sz;
580 
581 	sz = SSWF_JPG_BUFSIZE - jdst->dst.free_in_buffer;
582 	sswfWriteData(jdst, jdst->buffer, sz);
583 	//jdst->data->Write(jdst->buffer, sz);
584 }
585 
586 
587 
588 }		// extern "C"
589 
590 
591 
592 
593 /** \brief Load a JPEG image
594  *
595  * This function loads and decompresses a JPEG image.
596  *
597  * If you want to set an image in the TagImage, use SetFilename() instead.
598  *
599  * \note
600  * This function does not call OnError(). It is expected that you will use
601  * SetFilename() which generates errors as required. Note that the function
602  * specifically returns ErrorManager::ERROR_CODE_UNKNOWN_FORMAT if the
603  * image does not look like a JPEG. Other errors means that either there
604  * was an I/O error or the JPEG is corrupted.
605  *
606  * \param[in] filename	The name of the file to be loaded
607  * \param[in] im	The bitmap structure where the image is loaded
608  *
609  * \return An error code or ErrorManager::ERROR_CODE_NONE
610  *
611  * \sa sswf::TagImage::LoadTGA(const char *filename, image_t& im)
612  */
LoadJPEG(const char * filename,image_t & im)613 ErrorManager::error_code_t TagImage::LoadJPEG(const char *filename, image_t& im)
614 {
615 	sswf_jpg_error			jerr;
616 	struct jpeg_decompress_struct	cinfo;
617 	sswf_jpg_source			src;
618 	unsigned char			*s, *dst;
619 	long				i, size;
620 	unsigned long			sl;
621 	FILE				*f;
622 
623 /* try to open the JPEG file and ensure it is a JPEG! */
624 	f = fopen(filename, "rb");
625 	if(f == NULL) {
626 		return ErrorManager::ERROR_CODE_IO;
627 	}
628 	if(fread(src.buffer, 20, 1, f) != 1) {
629 		fclose(f);
630 		return ErrorManager::ERROR_CODE_IO;
631 	}
632 	if(src.buffer[ 0] != 0xFF
633 	|| src.buffer[ 1] != 0xD8
634 	|| src.buffer[ 2] != 0xFF
635 	/* a JPEG can start with any header, really!
636 	|| src.buffer[ 3] != 0xE0
637 	|| src.buffer[ 4] != 0x00
638 	|| src.buffer[ 5] != 0x10
639 	|| src.buffer[ 6] != 0x4A
640 	|| src.buffer[ 7] != 0x46
641 	|| src.buffer[ 8] != 0x49
642 	|| src.buffer[ 9] != 0x46
643 	|| src.buffer[10] != 0x00*/) {
644 		fclose(f);
645 		return ErrorManager::ERROR_CODE_UNKNOWN_FORMAT;
646 	}
647 	// rewind so the decompressor reads everything
648 	fseek(f, 0, SEEK_SET);
649 
650 /* setup the ugly error handler */
651 	cinfo.err = jpeg_std_error(&jerr.pub);
652 	jerr.pub.error_exit = sswfJPEGError;
653 	if(setjmp(jerr.setjmp_buffer)) {
654 		/* an error occured! */
655 		jpeg_destroy_decompress(&cinfo);
656 		fclose(f);
657 		return ErrorManager::ERROR_CODE_INVALID_IMAGE;
658 	}
659 
660 /* initialize the decompressor */
661 	jpeg_create_decompress(&cinfo);
662 
663 /* setup the input callbacks */
664 	src.src.init_source       = sswfInitSource;
665 	src.src.fill_input_buffer = sswfFillInputBuffer;
666 	src.src.skip_input_data   = sswfSkipInputData;
667 	src.src.resync_to_restart = sswfResyncToRestart;
668 	src.src.term_source       = sswfTermSource;
669 	src.file = f;
670 
671 	cinfo.src = &src.src;
672 
673 /* read the JPEG setup from the source file */
674 	jpeg_read_header(&cinfo, TRUE);
675 
676 /* ask for an RGB image (which is the usual default) */
677 	cinfo.out_color_space = JCS_RGB;
678 
679 /* start the decompressor (only after that call can we be sure of the output parameters) */
680 	jpeg_start_decompress(&cinfo);
681 
682 /* make sure we're getting an RGB image */
683 	if(cinfo.output_components != 3) {
684 		jpeg_destroy_decompress(&cinfo);
685 		fclose(f);
686 		return ErrorManager::ERROR_CODE_INVALID_IMAGE;
687 	}
688 
689 /* allocate the image in which the JPEG is read */
690 	im.f_alpha = false;
691 	im.f_width = cinfo.output_width;
692 	im.f_height = cinfo.output_height;
693 
694 	size = im.f_width * im.f_height;
695 	im.f_data = (unsigned char *) MemAlloc(size * 4, "buffer for image data (JPEG)");
696 
697 	dst = im.f_data;
698 	sl = cinfo.output_scanline + 1;
699 	while(cinfo.output_scanline != sl && cinfo.output_scanline < cinfo.output_height) {
700 		sl = cinfo.output_scanline;
701 		jpeg_read_scanlines(&cinfo, (JSAMPARRAY) &dst, 1);
702 
703 		// transform the RGB in RGBA
704 		i = cinfo.output_width;
705 		s = (unsigned char *) dst + i * 3;
706 		dst += i * 4;
707 		while(i > 0) {
708 			i--;
709 			s -= 3;
710 			dst -= 4;
711 			// WARNING: watch out! the order is important in the copy below!
712 			dst[3] = s[2];
713 			dst[2] = s[1];
714 			dst[1] = s[0];
715 			dst[0] = 255;
716 		}
717 		dst += cinfo.output_width * 4;
718 	}
719 
720 /* stop and free the decompressor */
721 	if(cinfo.output_scanline != sl) {
722 		jpeg_finish_decompress(&cinfo);
723 	}
724 	jpeg_destroy_decompress(&cinfo);
725 
726 	fclose(f);
727 
728 	return ErrorManager::ERROR_CODE_NONE;
729 }
730 
731 
732 
733 
734 
735 /** \brief Save a JPEG in a set of Data buffers.
736  *
737  * This function saves a JPEG image table encodings and compressed bits in
738  * two Data buffers.
739  *
740  * \param[in] encoding	Save the JPEG tables in this Data buffer
741  * \param[in] image	Save the JPEG compressed bits in this Data buffer
742  *
743  * \return An error or ErrorManager::ERROR_CODE_NONE
744  */
SaveJPEG(Data & encoding,Data & image)745 ErrorManager::error_code_t TagImage::SaveJPEG(Data& encoding, Data& image)
746 {
747 	sswf_jpg_error			jerr;
748 	struct jpeg_compress_struct	cinfo;
749 	sswf_jpg_destination		dst;
750 	const unsigned char		*s;
751 	unsigned char			*row, *d;
752 	long				sz;
753 
754 	row = 0;
755 
756 /* create the JPEG error handler */
757 	cinfo.err = jpeg_std_error(&jerr.pub);
758 	jerr.pub.error_exit = sswfJPEGError;
759 	if(setjmp(jerr.setjmp_buffer)) {
760 		/* an error occured */
761 		jpeg_destroy_compress(&cinfo);
762 		MemFree(row);
763 		return OnError(ErrorManager::ERROR_CODE_JPEG, "an error occured while compressing a JPEG image.");
764 	}
765 
766 /* create the compressor */
767 	jpeg_create_compress(&cinfo);
768 
769 /* set the output callbacks */
770 	dst.dst.init_destination =    sswfInitDestination;
771 	dst.dst.empty_output_buffer = sswfEmptyOutputBuffer;
772 	dst.dst.term_destination =    sswfTermDestination;
773 	dst.size = 0;
774 	dst.offset = 0;
775 	dst.state = 0;
776 	dst.encoding = &encoding;
777 	dst.image = &image;
778 
779 	cinfo.dest = &dst.dst;
780 
781 /* setup the compression parameters */
782 	cinfo.image_width      = f_image.f_width;
783 	cinfo.image_height     = f_image.f_height;
784 	cinfo.input_components = 3;				/* default to RGB 24 bits */
785 	cinfo.in_color_space   = JCS_RGB;			/* always required */
786 
787 	jpeg_set_defaults(&cinfo);
788 
789 /* any quality specified? */
790 	if(f_quality != 0) {				/* any quality definition? */
791 		jpeg_set_quality(&cinfo, f_quality, TRUE);
792 	}
793 
794 /* create a temporary row buffer */
795 	row = (unsigned char *) MemAlloc(cinfo.image_width * 3, "row used to read a JPEG image");
796 
797 /* compress the image */
798 	jpeg_start_compress(&cinfo, TRUE);
799 	s = f_image.f_data;
800 	while(cinfo.next_scanline < cinfo.image_height) {
801 		sz = cinfo.image_width;
802 		d = row;
803 		do {
804 			d[0] = s[1];
805 			d[1] = s[2];
806 			d[2] = s[3];
807 			d += 3;
808 			s += 4;
809 			sz--;
810 		} while(sz > 0);
811 		jpeg_write_scanlines(&cinfo, (JSAMPARRAY) &row, 1);
812 	}
813 
814 /* release the JPEG library structures */
815 	jpeg_finish_compress(&cinfo);
816 	jpeg_destroy_compress(&cinfo);
817 
818 	MemFree(row);
819 
820 	return ErrorManager::ERROR_CODE_NONE;
821 }
822 
823 
824 //********************************************************************************
825 //**********   JPEG Loader/Saver   ************************************* END *****
826 //********************************************************************************
827 
828 
829 
830 /** \brief Load a Targa image
831  *
832  * This function loads and decompresses a Targa image.
833  *
834  * If you want to set an image in the TagImage, use SetFilename() instead.
835  *
836  * \param[in] filename	The name of the file to be loaded
837  * \param[in] im	The bitmap structure where the image is loaded
838  *
839  * \return An error code or ErrorManager::ERROR_CODE_NONE
840  *
841  * \sa sswf::TagImage::LoadJPEG(const char *filename, image_t& im)
842  */
LoadTGA(const char * filename,image_t & im)843 ErrorManager::error_code_t TagImage::LoadTGA(const char *filename, image_t& im)
844 {
845 	unsigned char	header[18];
846 	long		width, height, depth, size, cnt, c, flags;
847 	unsigned char	*s, *d, temp;
848 	FILE		*f;
849 
850 	f = fopen(filename, "rb");
851 	if(f == NULL) {
852 		return ErrorManager::ERROR_CODE_IO;
853 	}
854 	if(fread(header, TGA_HEADER_SIZE, 1, f) != 1) {		// read the targa header
855 		fclose(f);
856 		return ErrorManager::ERROR_CODE_IO;
857 	}
858 
859 	width =  header[TGA_OFFSET_WIDTH_LO ] + header[TGA_OFFSET_WIDTH_HI ] * 256;
860 	height = header[TGA_OFFSET_HEIGHT_LO] + header[TGA_OFFSET_HEIGHT_HI] * 256;
861 	depth =  header[TGA_OFFSET_BITS_PER_PIXEL];
862 
863 	// for the flags, you should have bit 3 set when you include
864 	// some alpha; at this time I kind of ignore that...
865 	flags =  header[TGA_OFFSET_FLAGS];
866 	if(depth == 32) {
867 		flags &= ~8;
868 	}
869 
870 //printf(">>> Reading TGA file (%ld, %ld, %ld)\n", width, height, depth);
871 
872 	if(width == 0 || height == 0			// refuse wrong sizes
873 	|| (depth != 24 && depth != 32)			// only RGB and RGBA suppored
874 	|| header[TGA_OFFSET_COLORMAP_TYPE] != 0	// no colormap formats supported
875 	|| header[TGA_OFFSET_IMAGE_TYPE] != 2		// no compression supported
876 	|| (flags & ~0x20) != 0) {			// only accept top to bottom flag
877 		errno = EINVAL;
878 		fclose(f);
879 		return ErrorManager::ERROR_CODE_UNKNOWN_FORMAT;
880 	}
881 	depth /= 8;					// depth in bytes
882 
883 	if(header[TGA_OFFSET_IDENTIFIER_LENGTH] != 0) {
884 		// skip the comment
885 		fseek(f, header[TGA_OFFSET_IDENTIFIER_LENGTH], SEEK_CUR);
886 	}
887 
888 	im.f_alpha = depth == 4;
889 	im.f_width = width;
890 	im.f_height = height;
891 
892 	// read the data at once
893 	size = width * height;
894 	im.f_data = (unsigned char *) MemAlloc(size * 4, "buffer for image data");
895 	if(fread(im.f_data, size * depth, 1, f) != 1) {
896 		fclose(f);
897 		return ErrorManager::ERROR_CODE_IO;
898 	}
899 
900 	// we're done with the input file
901 	fclose(f);
902 
903 // TODO: I should swap the R and B in each loop and have only one loop!
904 	// images are saved in 32 bits in SWF even when only 24 are defined (use XRGB)
905 	if(depth == 3) {
906 		cnt = size;
907 		s = im.f_data + size * 3;
908 		d = im.f_data + size * 4;
909 		do {
910 			s -= 3;
911 			d -= 4;
912 			// watch out, the order is VERY important here (for the very 1st pixel)
913 			d[3] = s[2];
914 			d[2] = s[1];
915 			d[1] = s[0];
916 			d[0] = 255;		/* this IS taken in account even without the V3.0 tag!!! */
917 
918 #if 0
919 			if(d[1] == 255 && d[2] == 255 && d[3] == 255) {
920 				d[1] = 128;
921 				d[2] = 128;
922 				d[3] = 128;
923 			}
924 #endif
925 			cnt--;
926 		} while(cnt > 0);
927 	}
928 	else {
929 		// targas are saved as BGRA and we need ARGB instead
930 		// but we swap R and B later, so we generate ABGR
931 		cnt = size;
932 		d = im.f_data;
933 		do {
934 			temp = d[3];
935 			d[3] = d[2];
936 			d[2] = d[1];
937 			d[1] = d[0];
938 			d[0] = temp;
939 			d += 4;
940 			cnt--;
941 		} while(cnt > 0);
942 	}
943 
944 	// the red and blue are inverted in Targa files
945 	cnt = size;
946 	s = im.f_data;
947 	do {
948 		c = s[1];
949 		s[1] = s[3];
950 		s[3] = (char) c;
951 		s += 4;
952 		cnt--;
953 	} while(cnt > 0);
954 
955 	// flip the image vertically if necessary
956 	if((header[TGA_OFFSET_FLAGS] & 0x20) == 0) {
957 		cnt = height / 2;
958 		c = width * 4;
959 		s = im.f_data;
960 		d = s + size * 4;
961 		do {
962 			d -= c;
963 			swap(s, d, c);
964 			s += c;
965 			cnt--;
966 		} while(cnt > 0);
967 	}
968 
969 #if 0
970 	cnt = size;
971 	s = im.f_data;
972 	do {			/* shows that we have ARGB instead of RGBA as mentioned in the doc. */
973 		s[0] = 255 - (long) (sqrt((cnt % width) * (cnt % width) + (cnt / width) * (cnt / width)) * 255
974 								/ sqrt(width * width + height * height));
975 		s[1] = 0;
976 		s[2] = 0;
977 		s[3] = 0;
978 		s += 4;
979 		cnt--;
980 	} while(cnt > 0);
981 	im.f_alpha = 1;
982 #endif
983 #if 0
984 	cnt = width;
985 	s = im.f_data;
986 	d = s + size * 4;
987 	do {
988 		d -= 4;
989 		d[0] = 255;
990 		d[1] = 255;
991 		d[2] = 0;
992 		d[3] = 0;
993 		s[0] = 255;
994 		s[1] = 255;
995 		s[2] = 0;
996 		s[3] = 0;
997 		s += 4;
998 		cnt--;
999 	} while(cnt > 0);
1000 	cnt = height;
1001 	s = im.f_data;
1002 	d = s + width * 4;
1003 	do {
1004 		d[0 - 4] = 255;
1005 		d[1 - 4] = 0;
1006 		d[2 - 4] = 255;
1007 		d[3 - 4] = 0;
1008 		s[0] = 255;
1009 		s[1] = 255;
1010 		s[2] = 0;
1011 		s[3] = 0;
1012 		s += width * 4;
1013 		d += width * 4;
1014 		cnt--;
1015 	} while(cnt > 0);
1016 	cnt = height;
1017 	s = im.f_data + 10 * 4;
1018 	d = s + width * 4 - 20 * 4;
1019 	do {
1020 		d[0 - 4] = 255;
1021 		d[1 - 4] = 0;
1022 		d[2 - 4] = 255;
1023 		d[3 - 4] = 0;
1024 		s[0] = 255;
1025 		s[1] = 255;
1026 		s[2] = 0;
1027 		s[3] = 0;
1028 		s += width * 4;
1029 		d += width * 4;
1030 		cnt--;
1031 	} while(cnt > 0);
1032 #endif
1033 
1034 	return ErrorManager::ERROR_CODE_NONE;
1035 }
1036 
1037 
1038 
1039 /** \brief Set the alpha channel of an image
1040  *
1041  * This function takes an image and a mask as input and
1042  * copy the mask in the alpha channel of the image.
1043  *
1044  * The function works only if both images are exactly of
1045  * the same size (i.e. same width and height.)
1046  *
1047  * \param[in] im	The image receiving the mask as its alpha channel
1048  * \param[in] mask	The image used as the alpha channel
1049  *
1050  * \return An error code or ErrorManager::ERROR_CODE_NONE
1051  */
SetAlpha(image_t & im,const image_t & mask)1052 ErrorManager::error_code_t TagImage::SetAlpha(image_t& im, const image_t& mask)
1053 {
1054 	long			cnt;
1055 	const unsigned char	*s;
1056 	unsigned char		*d;
1057 
1058 	if(im.f_width != mask.f_width
1059 	|| im.f_height != mask.f_height) {
1060 		return OnError(ErrorManager::ERROR_CODE_SIZE_MISMATCH,
1061 			"the image and mask do not both have the same size (%ld, %ld) versus (%ld, %ld)",
1062 				im.f_width, im.f_height, mask.f_width, mask.f_height);
1063 	}
1064 
1065 	cnt = im.f_width * im.f_height;
1066 	s = mask.f_data;
1067 	d = im.f_data;
1068 	while(cnt > 0) {
1069 		d[0] = (s[1] + s[2] + s[3]) / 3;
1070 		if(d[0] != 255) {
1071 			/* We actually need to have the alpha already applied to
1072 			 * the components because the SWF players won't do it for you.
1073 			 * With OpenGL, you can use ONE for SRC and ONE_MINUS_SRC for
1074 			 * DST. This can make a difference in the resulting quality.
1075 			 * And using just the processor or MMX (or some equivalent)
1076 			 * you can save many instructions since the data is partially
1077 			 * processed already.
1078 			 */
1079 			im.f_alpha = true;
1080 			d[1] = (d[1] * d[0]) / 255;
1081 			d[2] = (d[2] * d[0]) / 255;
1082 			d[3] = (d[3] * d[0]) / 255;
1083 		}
1084 		s += 4;
1085 		d += 4;
1086 		cnt--;
1087 	}
1088 
1089 	return ErrorManager::ERROR_CODE_NONE;
1090 }
1091 
1092 
1093 /** \brief Load an image in the specified TagImage
1094  *
1095  * read one or two JPEG or targa files when filenames are specified
1096  *
1097  * \return An error code or ErrorManager::ERROR_CODE_NONE
1098  */
SetFilename(const char * image,const char * mask)1099 ErrorManager::error_code_t TagImage::SetFilename(const char *image, const char *mask)
1100 {
1101 	image_t				msk;
1102 	ErrorManager::error_code_t	ec;
1103 
1104 	f_count = 0;
1105 	MemClean(&f_colormap);
1106 	MemClean(&f_image.f_data);
1107 
1108 	ec = LoadJPEG(image, f_image);
1109 	if(ec == ErrorManager::ERROR_CODE_UNKNOWN_FORMAT) {
1110 		ec = LoadTGA(image, f_image);
1111 	}
1112 	if(ec != ErrorManager::ERROR_CODE_NONE) {
1113 		return ec;
1114 	}
1115 	if(!f_image.f_alpha && mask != 0) {
1116 		msk.f_data = 0;
1117 		ec = LoadJPEG(mask, msk);
1118 		if(ec == ErrorManager::ERROR_CODE_UNKNOWN_FORMAT) {
1119 			ec = LoadTGA(mask, msk);
1120 		}
1121 		if(ec != ErrorManager::ERROR_CODE_NONE) {
1122 			MemFree(msk.f_data);
1123 			return ec;
1124 		}
1125 		SetAlpha(f_image, msk);
1126 		MemFree(msk.f_data);
1127 	}
1128 
1129 //printf("Alpha = %d\n", f_image.f_alpha);
1130 
1131 	return ErrorManager::ERROR_CODE_NONE;
1132 }
1133 
1134 
1135 
1136 /** \brief Set an image in the TagImage object
1137  *
1138  * This function saves the specified image in the TagImage object.
1139  *
1140  * The image is specified by all of its characteristics: width,
1141  * height, buffer (data), whether it includes an alpha channel
1142  * and whether it has a colormap.
1143  *
1144  * The data pointer is saved as is in the image structure. This
1145  * means the TagImage becomes the owner of that pointer. It will
1146  * automatically free it with a call to MemFree().
1147  *
1148  * It is expected that you use your image memory allocator to
1149  * allocate this buffer:
1150  *
1151  * \code
1152  *	TagImage my_image;
1153  *
1154  *	...
1155  *	data = my_image->MemAlloc(width * height * 4, "My Image");
1156  *	...
1157  *	my_image->SetImage(...);
1158  *	...
1159  *	// MemFree(data) -- done by the TagImage destructor when necessary
1160  *	...
1161  * \endcode
1162  *
1163  * \todo
1164  * The colormap parameter is currently ignored.
1165  *
1166  * \param[in] width	The width of the image
1167  * \param[in] height	The height of the image
1168  * \param[in] data	The pointer to the data buffer (ARGB)
1169  * \param[in] alpha	Whether the alpha channel is valid
1170  * \param[in] count	The size of the colormap
1171  * \param[in] colormap	The colors in the colormap (RGBA)
1172  */
SetImage(long width,long height,unsigned char * data,bool alpha,long count,unsigned char * colormap)1173 void TagImage::SetImage(long width, long height, unsigned char *data, bool alpha, long count, unsigned char *colormap)
1174 {
1175 	MemClean(&f_colormap);
1176 	MemClean(&f_image.f_data);
1177 
1178 	f_image.f_alpha = alpha;
1179 	f_image.f_width = width;
1180 	f_image.f_height = height;
1181 	f_count = count;
1182 	f_colormap = colormap;
1183 	f_image.f_data = data;
1184 }
1185 
1186 
1187 
1188 /** \brief Check that the image can be saved.
1189  *
1190  * This function makes sure that the image format was defined
1191  * and depending on the format and whether it uses an alpha
1192  * channel, decides whether the minimum version is 2 or 3.
1193  *
1194  * \return An error code or ErrorManager::ERROR_CODE_NONE
1195  */
PreSave(void)1196 ErrorManager::error_code_t TagImage::PreSave(void)
1197 {
1198 	switch(f_format) {
1199 	//case IMAGE_FORMAT_LOSSLESS_8: -- we don't support this one yet...
1200 	case IMAGE_FORMAT_LOSSLESS_16:
1201 		MinimumVersion(2);
1202 		break;
1203 
1204 	case IMAGE_FORMAT_LOSSLESS_BEST:
1205 	case IMAGE_FORMAT_LOSSLESS_32:
1206 	case IMAGE_FORMAT_JPEG:
1207 		MinimumVersion(f_image.f_alpha ? 3 : 2);
1208 		break;
1209 
1210 	default:
1211 		return OnError(ErrorManager::ERROR_CODE_UNSUPPORTED_IMAGE_FORMAT, "the specified image format is not supported or still undefined.");
1212 
1213 	}
1214 
1215 	return ErrorManager::ERROR_CODE_NONE;
1216 }
1217 
1218 
1219 
1220 /** \brief Save the image in the specified Data buffer.
1221  *
1222  * This function saves the image in the specified Data buffer.
1223  * Whenever saving the image in one of the Lossless formats,
1224  * the function tries to transform it to a paletted image
1225  * since in general a paletted image can be saved in a
1226  * smaller image.
1227  *
1228  * \bug
1229  * At this time, the function does not support LOSSLESS8.
1230  *
1231  * \return An error code or ErrorManager::ERROR_CODE_NONE
1232  */
Save(Data & data)1233 ErrorManager::error_code_t TagImage::Save(Data& data)
1234 {
1235 	long				size, count, idx, w, h, adjusted_width;
1236 	ErrorManager::error_code_t	ec;
1237 	unsigned short			c16, *b16;
1238 	unsigned char			*s, *d, *b8, palette[256 * 4];
1239 	uLongf				sz;
1240 	Data				jpeg_encoding, jpeg_image;
1241 
1242 	switch(f_format) {
1243 	case IMAGE_FORMAT_LOSSLESS_8:
1244 		assert(0, "Lossless 8 format not supported yet (no quantisation available)");
1245 		return OnError(ErrorManager::ERROR_CODE_UNSUPPORTED_IMAGE_FORMAT, "the specified image format is not supported or still undefined.");
1246 		/* TODO: we need to generate a palette...
1247 		size = ((f_image.f_width + 1) & -2) * f_image.f_height;
1248 		b8 = (unsigned char *) MemAlloc(size, "8 bits image");
1249 		s = f_image.f_data;
1250 		d = (unsigned char *) b8;
1251 		sz = size / 2;
1252 		do {
1253 			d[0] = (s[1] + s[2] + s[3]) / 3;
1254 			d += 1;
1255 			s += 4;
1256 			sz--;
1257 		} while(sz > 0);
1258 		sz = (size * 11) / 10 + 256;		// buffer + 10% + 256 bytes
1259 		d = (unsigned char *) MemAlloc(sz, "compressed image buffer");
1260 		compress((Bytef *) d, &sz, (const Bytef *) b8, size);
1261 		MemFree(b8);	// done with the temp. buffer
1262 		// here we can compute the exact size without using a sub_data!
1263 		size = 2 + 1 + 2 + 2 + sz;
1264 		SaveTag(data, SWF_TAG_DEFINE_BITS_LOSSLESS, size);
1265 		SaveID(data);
1266 		data.PutByte(3);	// format - 8 bits
1267 		data.PutShort(f_image.f_width);
1268 		data.PutShort(f_image.f_height);
1269 		data.Write(d, sz);
1270 		MemFree(d);
1271 		*/
1272 		break;
1273 
1274 	case IMAGE_FORMAT_LOSSLESS_16:
1275 lossless_16:
1276 		adjusted_width = (f_image.f_width + 1) & -2;
1277 		size = adjusted_width * f_image.f_height * 2;
1278 		b16 = (unsigned short *) MemAlloc(size, "16 bits image");
1279 		s = f_image.f_data;
1280 		d = (unsigned char *) b16;
1281 		h = 0;
1282 		do {
1283 			w = f_image.f_width;
1284 			do {
1285 				c16 = ((s[1] & 0xF8) << 7) | ((s[2] & 0xF8) << 2) | ((s[3] & 0xF8) >> 3);
1286 				d[0] = c16 >> 8;
1287 				d[1] = (char) c16;
1288 				d += 2;
1289 				s += 4;
1290 				w--;
1291 			} while(w > 0);
1292 			if((f_image.f_width & 1) != 0) {
1293 				d[0] = 0;
1294 				d[1] = 0;
1295 				d += 2;
1296 			}
1297 			h++;
1298 		} while(h < f_image.f_height);
1299 		sz = (size * 11) / 10 + 256;		// buffer + 10% + 256 bytes
1300 		d = (unsigned char *) MemAlloc(sz, "compressed image buffer");
1301 		compress((Bytef *) d, &sz, (const Bytef *) b16, size);
1302 		MemFree(b16);	// done with the temp. buffer
1303 		// here we can compute the exact size without using a sub_data!
1304 		size = 2 + 1 + 2 + 2 + sz;
1305 		SaveTag(data, SWF_TAG_DEFINE_BITS_LOSSLESS, size);
1306 		SaveID(data);
1307 		data.PutByte(4);	/* format - 16 bits */
1308 		data.PutShort((short) f_image.f_width);
1309 		data.PutShort((short) f_image.f_height);
1310 		data.Write(d, sz);
1311 		MemFree(d);
1312 		break;
1313 
1314 	case IMAGE_FORMAT_LOSSLESS_BEST:
1315 		// first try with a palette
1316 		count = 0;
1317 		adjusted_width = (f_image.f_width + 3) & -4;
1318 		size = adjusted_width * f_image.f_height + 256 * 4;
1319 		b8 = (unsigned char *) MemAlloc(size, "8 bits image & space for palette");
1320 		memset(b8, 0, size);	// better compression if pads are zeroes
1321 		h = f_image.f_height;
1322 		s = f_image.f_data;
1323 		h = 0;
1324 		do {
1325 			w = f_image.f_width;
1326 			// the 256 * 4 is to skip the space for the palette
1327 			d = b8 + h * adjusted_width + 256 * 4;
1328 			do {
1329 				idx = count;
1330 				while(idx > 0) {
1331 					idx--;
1332 					if(palette[idx * 4 + 3] == s[0]
1333 					&& palette[idx * 4 + 0] == s[1]
1334 					&& palette[idx * 4 + 1] == s[2]
1335 					&& palette[idx * 4 + 2] == s[3]) {
1336 						*d = (unsigned char) idx;
1337 						goto found;
1338 					}
1339 				}
1340 				if(count == 256) {
1341 #if 0
1342 // use this to force a colormap and make sure you test this case...
1343 					*d = 0;
1344 					goto found;
1345 #endif
1346 					goto not_paletted;
1347 				}
1348 				palette[count * 4 + 3] = s[0];
1349 				palette[count * 4 + 0] = s[1];
1350 				palette[count * 4 + 1] = s[2];
1351 				palette[count * 4 + 2] = s[3];
1352 				*d = (unsigned char) count;
1353 				count++;
1354 found:
1355 				d++;
1356 				s += 4;
1357 				w--;
1358 			} while(w > 0);
1359 			h++;
1360 		} while(h < f_image.f_height);
1361 		/* this did work, save as an 8 bits paletted image! */
1362 		// stick the palette right before the data
1363 		// (b8 will usually start with undefined data)
1364 		if(f_image.f_alpha) {
1365 			s = b8 + (256 - count) * 4;
1366 			memcpy(s, palette, count * 4);
1367 		}
1368 		else {
1369 			s = b8 + 256 * 4 - count * 3;
1370 			for(idx = 0; idx < count; idx++) {
1371 				s[idx * 3 + 0] = palette[idx * 4 + 0];
1372 				s[idx * 3 + 1] = palette[idx * 4 + 1];
1373 				s[idx * 3 + 2] = palette[idx * 4 + 2];
1374 			}
1375 		}
1376 		size = d - s;
1377 		sz = (size * 11) / 10 + 256;		// buffer + 10% + 256 bytes
1378 		d = (unsigned char *) MemAlloc(sz, "compressed image buffer");
1379 		compress((Bytef *) d, &sz, (const Bytef *) s, size);
1380 		MemFree(b8);	// done with the temp. buffer
1381 		// here we can compute the exact size without using a sub_data!
1382 		size = 2 + 1 + 2 + 2 + 1 + sz;
1383 		SaveTag(data, f_image.f_alpha ? SWF_TAG_DEFINE_BITS_LOSSLESS2 : SWF_TAG_DEFINE_BITS_LOSSLESS, size);
1384 		SaveID(data);
1385 		data.PutByte(3);	// format - 8 bits
1386 		data.PutShort((short) f_image.f_width);
1387 		data.PutShort((short) f_image.f_height);
1388 		data.PutByte(count - 1);
1389 		data.Write(d, sz);
1390 		MemFree(d);
1391 		break;
1392 
1393 not_paletted:
1394 		if(!f_image.f_alpha) {
1395 			/* test if we could use 16 bits (RGB555) instead */
1396 			count = 0;
1397 			sz = size = f_image.f_width * f_image.f_height;
1398 			do {
1399 				if((s[1] & 7) != 0 || (s[2] & 7) != 0 || (s[3] & 7) != 0) {
1400 					count++;
1401 				}
1402 				s += 4;
1403 				sz--;
1404 			} while(sz > 0);
1405 			if(count <= size / 10) {
1406 				/* less than 10% of loss, do it! */
1407 				goto lossless_16;
1408 			}
1409 		}
1410 		/*FALLTHROUGH*/
1411 	case IMAGE_FORMAT_LOSSLESS_32:
1412 		size = f_image.f_width * f_image.f_height * 4;
1413 		sz = (size * 11) / 10 + 256;		// buffer + 10% + 256 bytes
1414 		d = (unsigned char *) MemAlloc(sz, "compressed image buffer");
1415 		compress((Bytef *) d, &sz, (const Bytef *) f_image.f_data, size);
1416 
1417 		// here we can compute the exact size without using a sub_data!
1418 		size = 2 + 1 + 2 + 2 + sz;
1419 		SaveTag(data, f_image.f_alpha ? SWF_TAG_DEFINE_BITS_LOSSLESS2 : SWF_TAG_DEFINE_BITS_LOSSLESS, size);
1420 
1421 		SaveID(data);
1422 		data.PutByte(5);	/* format - 32 bits */
1423 		data.PutShort((short) f_image.f_width);
1424 		data.PutShort((short) f_image.f_height);
1425 		data.Write(d, sz);
1426 
1427 		MemFree(d);
1428 		break;
1429 
1430 	case IMAGE_FORMAT_JPEG:
1431 		// we need a sub data because we can't infer the size of
1432 		// the result before it is actually saved in a data buffer
1433 		ec = SaveJPEG(jpeg_encoding, jpeg_image);
1434 		if(ec != ErrorManager::ERROR_CODE_NONE) {
1435 			return ec;
1436 		}
1437 
1438 		if(f_image.f_alpha) {
1439 			size = f_image.f_width * f_image.f_height;
1440 			b8 = (unsigned char *) MemAlloc(size, "alpha channel buffer");
1441 			s = f_image.f_data;
1442 			d = b8;
1443 			sz = size;
1444 			do {
1445 				*d++ = s[0];
1446 				s += 4;
1447 				sz--;
1448 			} while(sz > 0);
1449 			sz = (size * 11) / 10 + 256;		// buffer + 10% + 256 bytes
1450 			d = (unsigned char *) MemAlloc(sz, "compressed image buffer");
1451 			compress((Bytef *) d, &sz, (const Bytef *) b8, size);
1452 
1453 			MemFree(b8);
1454 
1455 			size = 2 + 4 + jpeg_encoding.ByteSize() + jpeg_image.ByteSize() + sz;
1456 			SaveTag(data, SWF_TAG_DEFINE_BITS_JPEG3, size);
1457 
1458 			SaveID(data);
1459 			data.PutLong(jpeg_encoding.ByteSize() + jpeg_image.ByteSize());
1460 			data.Append(jpeg_encoding);
1461 			data.Append(jpeg_image);
1462 			data.Write(d, sz);
1463 
1464 			MemFree(d);
1465 		}
1466 		else {
1467 			size = 2 + jpeg_encoding.ByteSize() + jpeg_image.ByteSize();
1468 			SaveTag(data, SWF_TAG_DEFINE_BITS_JPEG2, size);
1469 
1470 			SaveID(data);
1471 			data.Append(jpeg_encoding);
1472 			data.Append(jpeg_image);
1473 		}
1474 
1475 		break;
1476 
1477 	default:
1478 		assert(0, "unknown image format");
1479 		return OnError(ErrorManager::ERROR_CODE_UNSUPPORTED_IMAGE_FORMAT, "the specified image format is not supported or still undefined.");
1480 		/*NOTREACHED*/
1481 
1482 	}
1483 
1484 	return ErrorManager::ERROR_CODE_NONE;
1485 }
1486 
1487 
1488 
1489 
1490 
1491 /* The following options fold the documentation; use 'zi' to turn on and off
1492  *
1493  * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
1494  */
1495