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—DefineJPEGTables</a>
76 * \sa <a href="../SWFalexref.html#tag_definebitsjpeg">SWF Alexis' Reference—DefineBitsJPEG</a>
77 * \sa <a href="../SWFalexref.html#tag_definebitsjpeg2">SWF Alexis' Reference—DefineBitsJPEG2</a>
78 * \sa <a href="../SWFalexref.html#tag_definebitsjpeg3">SWF Alexis' Reference—DefineBitsJPEG3</a>
79 * \sa <a href="../SWFalexref.html#tag_definebitslossless">SWF Alexis' Reference—DefineBitsLossless</a>
80 * \sa <a href="../SWFalexref.html#tag_definebitslossless2">SWF Alexis' Reference—DefineBitsLossless2</a>
81 * \sa <a href="../SWFalexref.html#swf_tag">SWF Alexis' Reference—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 = ℑ
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