Update procedures
[shapes.git] / source / import_png.cc
blob33a732c87daa9538dcb146043360648c55af1a39
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2009, 2010 Henrik Tidefelt
19 #include "config.h"
21 #ifdef HAVE_LIBPNG
22 /* Placing this inclusion first could be a dangerous way of avoiding a relevant warning
23 * about possibly conflicting uses of setjmp.h. See libpng/pngconf.h for for information.
25 #include <png.h>
26 #endif
28 #include "drawabletypes.h"
29 #include "rasterloaders.h"
30 #include "statetypes.h"
31 #include "autoonoff.h"
32 #include "globals.h"
33 #include "consts.h"
34 #include "warn.h"
36 #include <fstream>
38 using namespace Shapes;
41 #ifdef HAVE_LIBPNG
43 namespace Shapes
45 namespace Kernel
48 void
49 Shapes_pnglib_error_fn( png_structp png_ptr,
50 png_const_charp error_msg )
52 throw Exceptions::ExternalError( strrefdup( error_msg ) );
55 void
56 Shapes_pnglib_warning_fn( png_structp png_ptr,
57 png_const_charp warn_msg )
59 std::ostringstream msg;
60 msg << "libpng says " << warn_msg ;
61 WARN_OR_THROW( Exceptions::ExternalError( strrefdup( msg ), true ) );
64 void
65 Shapes_pnglib_read_data( png_structp png_ptr,
66 png_bytep data,
67 png_size_t length )
69 std::istream * iFile = static_cast< std::istream * >( png_get_io_ptr( png_ptr ) );
70 iFile->read( reinterpret_cast< char * >( data ), length );
75 namespace Helpers
78 void separateAlpha_bits( const unsigned char * row, size_t rowBytes, size_t bitsPerUnit, std::ostream & colorDst, size_t colorUnits, std::ostream & alphaDst, size_t alphaUnits, const png_color_16 * transparentColor, char * buf1, char * buf2 );
79 template< class C >
80 void separateAlpha( const unsigned char * row, size_t rowBytes, std::ostream & colorDst, size_t colorUnts, std::ostream & alphaDst, size_t alphaUnits, const png_color_16 * transparentColor, char * buf1, char * buf2 );
81 void applyPalette( const unsigned char * row, size_t rowBytes, size_t index_depth, const png_colorp palette, const png_bytep trans, int num_palette, std::ostream & colorDst, std::ostream & alphaDst );
86 #endif
89 RefCountPtr< const Lang::RasterImage >
90 Shapes::Helpers::RasterLoader_PNG::load( RefCountPtr< std::ifstream > & filePtr, const std::string & full_filename, Concrete::Length resolution, bool override, const Ast::PlacedIdentifier & coreId, const Ast::SourceLocation & callLoc ) const
92 #ifndef HAVE_LIBPNG
93 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_LIBPNG, coreId, callLoc );
94 #else
96 std::ifstream & iFile = *filePtr;
98 const size_t SIGNATURE_SIZE = 8;
100 char header[ SIGNATURE_SIZE + 1 ];
101 iFile.read( header, SIGNATURE_SIZE );
102 bool is_png = png_sig_cmp( reinterpret_cast< png_bytep >( header ), 0, SIGNATURE_SIZE ) == 0;
103 if( ! is_png )
105 throw Exceptions::CoreRequirement( "The imported file does not have the magic signature of a PNG file.", coreId, callLoc );
109 png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
110 static_cast< png_voidp >( 0 ), /* Pointer to additional information passed to error and warning handlers? */
111 Kernel::Shapes_pnglib_error_fn,
112 Kernel::Shapes_pnglib_warning_fn );
114 /* We use two error handling mechanisms in parallel, since I don't understand exactly how to use the longjmp function in the uer-defined
115 * error handler Shapes_pnglib_error_fn. Hence, we both use setjmp in case someone uses longjmp, and use try/catch to handle the errors
116 * thrown by Shapes_pnglib_error_fn.
119 png_set_error_fn( png_ptr,
120 static_cast< png_voidp >( 0 ), /* Pointer to additional information passed to error and warning handlers? */
121 Kernel::Shapes_pnglib_error_fn,
122 Kernel::Shapes_pnglib_warning_fn);
124 if( png_ptr == 0)
126 throw Exceptions::ExternalError( "Failed to allocate read structure for reading a PNG file." );
129 png_infop info_ptr = png_create_info_struct( png_ptr );
130 if( info_ptr == 0)
132 png_destroy_read_struct( & png_ptr,
133 static_cast< png_infopp >( 0 ), static_cast< png_infopp >( 0 ) );
134 throw Exceptions::ExternalError( "Failed to allocate info structure for reading a PNG file." );
137 png_infop end_info = png_create_info_struct( png_ptr );
138 if( end_info == 0 )
140 png_destroy_read_struct( & png_ptr, & info_ptr,
141 static_cast< png_infopp >( 0 ) );
142 throw Exceptions::ExternalError( "Failed to allocate end-info structure for reading a PNG file." );
145 if( setjmp( png_jmpbuf( png_ptr ) ) )
147 png_destroy_read_struct( & png_ptr, & info_ptr, & end_info );
148 throw Exceptions::ExternalError( "Caught a longjmp from libpng while reading a PNG file." );
153 png_set_sig_bytes( png_ptr, SIGNATURE_SIZE );
155 png_set_read_fn( png_ptr,
156 static_cast< png_voidp >( filePtr.getPtr( ) ),
157 Kernel::Shapes_pnglib_read_data );
160 png_read_png( png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0 );
162 png_uint_32 size_x;
163 png_uint_32 size_y;
164 int size_depth;
165 int color_type;
166 int interlace_method;
167 int compression_method;
168 int filter_method;
170 png_get_IHDR( png_ptr, info_ptr,
171 & size_x, & size_y, & size_depth,
172 & color_type, & interlace_method, & compression_method, & filter_method );
174 RefCountPtr< const Lang::ColorSpace > colorSpace = Lang::THE_COLOR_SPACE_DEVICE_GRAY; /* Initialize with anything. */
175 bool hasAlpha = false;
176 bool hasTransparentColor = false;
177 bool hasPalette = false;
178 png_colorp palette;
179 int num_palette;
180 switch( color_type )
182 case PNG_COLOR_TYPE_GRAY:
183 /* Use the default value set above! */
184 break;
185 case PNG_COLOR_TYPE_RGB:
186 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_RGB;
187 break;
188 case PNG_COLOR_TYPE_GRAY_ALPHA:
189 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_GRAY;
190 hasAlpha = true;
191 break;
192 case PNG_COLOR_TYPE_RGB_ALPHA:
193 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_RGB;
194 hasAlpha = true;
195 break;
196 case PNG_COLOR_TYPE_PALETTE:
197 /* The palette colors use 8 bit in each of the three channels. */
198 colorSpace = Lang::THE_COLOR_SPACE_DEVICE_RGB;
199 png_get_PLTE( png_ptr, info_ptr, & palette, & num_palette );
200 hasPalette = true;
201 break;
202 default:
203 throw Exceptions::CoreRequirement( "The PNG file was using an unknown color type value.", coreId, callLoc );
206 png_bytep tRNS_trans;
207 png_color_16p tRNS_trans_values;
208 if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) != 0 )
210 hasAlpha = true;
211 int tRNS_num_trans;
212 png_get_tRNS( png_ptr, info_ptr, & tRNS_trans, & tRNS_num_trans, & tRNS_trans_values );
213 if( hasPalette )
215 if( tRNS_num_trans != num_palette )
217 throw Exceptions::CoreRequirement( "The PNG file has a transparency pallete of different size compared to the color palette.", coreId, callLoc );
220 else
222 hasTransparentColor = true;
226 size_t components = colorSpace->numberOfComponents( );
227 size_t png_channels = png_get_channels( png_ptr, info_ptr );
229 Concrete::Length resolution_x = resolution;
230 Concrete::Length resolution_y = resolution;
231 if( ! override && png_get_valid( png_ptr, info_ptr, PNG_INFO_pHYs ) != 0 )
233 png_uint_32 x_pixels_per_unit;
234 png_uint_32 y_pixels_per_unit;
235 int phys_unit_type;
236 png_get_pHYs( png_ptr, info_ptr, & x_pixels_per_unit, & y_pixels_per_unit, & phys_unit_type );
237 switch( phys_unit_type )
239 case PNG_RESOLUTION_UNKNOWN:/* Only aspect ratio. */
241 Concrete::Length tmpRes = sqrt( static_cast< double >( x_pixels_per_unit ) * static_cast< double >( y_pixels_per_unit ) ) * resolution;
242 resolution_x = ( tmpRes / x_pixels_per_unit );
243 resolution_y = ( tmpRes / y_pixels_per_unit );
245 break;
246 case PNG_RESOLUTION_METER:/* Dots per meter. */
248 resolution_x = ( Concrete::Length( 100/(2.54/72) ) / x_pixels_per_unit );
249 resolution_y = ( Concrete::Length( 100/(2.54/72) ) / y_pixels_per_unit );
251 break;
252 default:
253 throw Exceptions::CoreRequirement( "The PNG file was using an unknown density unit value.", coreId, callLoc );
257 Lang::RasterImage * imagePtr = Lang::RasterImage::newInstance( size_x, size_y, hasPalette ? 8 : size_depth, resolution_x, resolution_y, colorSpace );
258 RefCountPtr< const Lang::RasterImage > image = RefCountPtr< const Lang::RasterImage >( RefCountPtr< const Lang::RasterImage >( imagePtr ) );
260 RefCountPtr< SimplePDF::PDF_Stream_out > maskStream = RefCountPtr< SimplePDF::PDF_Stream_out >( NullPtr< SimplePDF::PDF_Stream_out >( ) );
262 SimplePDF::PDF_Stream_out & stream = *(imagePtr->stream( ));
263 stream[ "Filter" ] = SimplePDF::newName( "FlateDecode" );
264 if( hasAlpha )
266 Lang::RasterImage * maskPtr = Lang::RasterImage::newInstance( size_x, size_y, hasPalette ? 8 : size_depth, resolution_x, resolution_y, Lang::THE_COLOR_SPACE_DEVICE_GRAY );
267 imagePtr->setSoftMask( RefCountPtr< const Lang::RasterImage >( RefCountPtr< const Lang::RasterImage >( maskPtr ) ) );
268 maskStream = maskPtr->stream( );
269 (*maskStream)[ "Filter" ] = SimplePDF::newName( "FlateDecode" );
271 const SimplePDF::PDF_Version::Version SOFTMASK_VERSION = SimplePDF::PDF_Version::PDF_1_4;
272 if( Kernel::the_PDF_version.greaterOrEqual( SOFTMASK_VERSION ) )
274 stream[ "SMask" ] = maskPtr->getResource( );
276 else
278 Kernel::the_PDF_version.message( SOFTMASK_VERSION, "A PNG alpha channel (soft mask) was ignored." );
282 size_t rowbytes = png_get_rowbytes( png_ptr, info_ptr );
283 char * buf1 = 0;
284 char * buf2 = 0;
285 PossiblyDeleteOnExit< char > buf1Deleter;
286 PossiblyDeleteOnExit< char > buf2Deleter;
287 if( hasAlpha )
289 buf1 = new char[ rowbytes ];
290 buf1Deleter.activate( buf1 );
291 buf2 = new char[ rowbytes ];
292 buf2Deleter.activate( buf2 );
294 png_bytep * rowBegin = png_get_rows( png_ptr, info_ptr );
295 for( png_bytep * srcRow = rowBegin; srcRow < rowBegin + size_y; ++srcRow )
297 /* Note that image data in PDF starts each row on a fresh byte boundary.
299 if( hasPalette )
301 if( hasAlpha )
303 Helpers::applyPalette( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, size_depth, palette, tRNS_trans, num_palette, stream.data, maskStream->data );
305 else
307 std::ostringstream ignore;
308 Helpers::applyPalette( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, size_depth, palette, 0, num_palette, stream.data, ignore );
311 else if( hasAlpha )
313 if( hasTransparentColor )
315 /* There may be some kind of filler (byte or bits) in the data, that we need to discard. */
316 switch( size_depth )
318 case 1:
319 case 2:
320 case 4:
321 Helpers::separateAlpha_bits( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, size_depth, stream.data, components, maskStream->data, png_channels - components, tRNS_trans_values, buf1, buf2 );
322 break;
323 case 8:
324 Helpers::separateAlpha< png_byte >( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, stream.data, components, maskStream->data, png_channels - components, tRNS_trans_values, buf1, buf2 );
325 break;
326 case 16:
327 Helpers::separateAlpha< png_uint_16 >( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, stream.data, components, maskStream->data, png_channels - components, tRNS_trans_values, buf1, buf2 );
328 break;
329 default:
330 throw Exceptions::InternalError( "Unexpected color depth in PNG image." );
333 else
335 switch( size_depth )
337 case 1:
338 case 2:
339 case 4:
340 Helpers::separateAlpha_bits( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, size_depth, stream.data, components, maskStream->data, 1, 0, buf1, buf2 );
341 break;
342 case 8:
343 Helpers::separateAlpha< png_byte >( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, stream.data, components, maskStream->data, 1, 0, buf1, buf2 );
344 break;
345 case 16:
346 Helpers::separateAlpha< png_uint_16 >( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, stream.data, components, maskStream->data, 1, 0, buf1, buf2 );
347 break;
348 default:
349 throw Exceptions::InternalError( "Unexpected color depth in PNG image." );
353 else if( png_channels > components )
355 /* There is some kind of filler (byte or bits) in the data, that we need to discard. */
356 std::ostringstream ignore;
357 switch( size_depth )
359 case 1:
360 case 2:
361 case 4:
362 Helpers::separateAlpha_bits( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, size_depth, stream.data, components, ignore, png_channels - components, 0, buf1, buf2 );
363 break;
364 case 8:
365 Helpers::separateAlpha< png_byte >( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, stream.data, components, ignore, png_channels - components, 0, buf1, buf2 );
366 break;
367 case 16:
368 Helpers::separateAlpha< png_uint_16 >( reinterpret_cast< unsigned char * >( *srcRow ), rowbytes, stream.data, components, ignore, png_channels - components, 0, buf1, buf2 );
369 break;
370 default:
371 throw Exceptions::InternalError( "Unexpected color depth in PNG image." );
374 else
376 stream.data.write( reinterpret_cast< char * >( *srcRow ), rowbytes );
380 /* If everything was OK, we just free allocated resources and return.
382 png_destroy_read_struct( & png_ptr, & info_ptr, & end_info );
384 return image;
386 catch( const Exceptions::Exception & ball )
388 png_destroy_read_struct( & png_ptr, & info_ptr, & end_info );
389 throw;
391 #endif
395 #ifdef HAVE_LIBPNG
397 void
398 Helpers::separateAlpha_bits( const unsigned char * row, size_t rowBytes, size_t bitsPerUnit, std::ostream & colorDst, size_t colorUnits, std::ostream & alphaDst, size_t alphaUnits, const png_color_16 * transparentColor, char * bufCo, char * bufAl )
400 char * dstCo = bufCo;
401 char * dstAl = bufAl;
403 png_uint_16 transparentColorArray[3];
404 if( transparentColor != 0 )
406 switch( colorUnits )
408 case 1:
409 transparentColorArray[0] = transparentColor->gray;
410 break;
411 case 3:
412 transparentColorArray[0] = transparentColor->red;
413 transparentColorArray[1] = transparentColor->green;
414 transparentColorArray[2] = transparentColor->blue;
415 break;
416 default:
417 throw Exceptions::InternalError( "Unexpected number of color channels in PNG image alpha bit separation." );
420 const unsigned char * src = row;
421 const unsigned char * srcEnd = row + rowBytes;
422 unsigned char srcByte = *src;
423 ++src;
424 unsigned char dstByteCo = 0; /* Initialize to inhibit compiler warnings. */
425 unsigned char dstByteAl = 0; /* Initialize to inhibit compiler warnings. */
426 unsigned char srcShift = 8 - bitsPerUnit;
427 unsigned char dstAvailCo = 8;
428 unsigned char dstAvailAl = 8;
429 unsigned char mask;
430 switch( bitsPerUnit )
432 case 1:
433 mask = 0x01;
434 break;
435 case 2:
436 mask = 0x03;
437 break;
438 case 4:
439 mask = 0x07;
440 break;
441 default:
442 throw Exceptions::InternalError( "Unexpected color depth in PNG image alpha bit separation." );
444 while( true )
446 bool trans = true;
447 const png_uint_16 * transparentColorSrc = transparentColorArray;
448 for( size_t i = 0; i < colorUnits; ++i, ++transparentColorSrc )
450 dstByteCo = ( dstByteCo << bitsPerUnit ) | ( ( srcByte >> srcShift ) & mask );
451 if( transparentColor != 0 && ( ( srcByte >> srcShift ) & mask ) != *transparentColorSrc )
453 trans = false;
455 dstAvailCo -= bitsPerUnit;
456 if( dstAvailCo == 0 )
458 *reinterpret_cast< unsigned char * >( dstCo ) = dstByteCo;
459 ++dstCo;
460 dstAvailCo = 8;
462 if( srcShift == 0 )
464 if( src == srcEnd )
466 goto srcComplete;
468 srcByte = *src;
469 ++src;
470 srcShift = 8;
472 srcShift -= bitsPerUnit;
474 if( transparentColor == 0 )
476 for( size_t i = 0; i < alphaUnits; ++i )
478 dstByteAl = ( dstByteAl << bitsPerUnit ) | ( ( srcByte >> srcShift ) & mask );
479 dstAvailAl -= bitsPerUnit;
480 if( dstAvailAl == 0 )
482 *reinterpret_cast< unsigned char * >( dstAl ) = dstByteAl;
483 ++dstAl;
484 dstAvailAl = 8;
486 if( srcShift == 0 )
488 if( src == srcEnd )
490 goto srcComplete;
492 srcByte = *src;
493 ++src;
494 srcShift = 8;
496 srcShift -= bitsPerUnit;
499 else
501 dstByteAl = ( dstByteAl << bitsPerUnit ) | ( trans ? mask : 0 );
502 dstAvailAl -= bitsPerUnit;
503 if( dstAvailAl == 0 )
505 *reinterpret_cast< unsigned char * >( dstAl ) = dstByteAl;
506 ++dstAl;
507 dstAvailAl = 8;
510 /* Just ignore filler data. */
511 for( size_t i = 0; i < alphaUnits; ++i )
513 if( srcShift == 0 )
515 if( src == srcEnd )
517 goto srcComplete;
519 srcByte = *src;
520 ++src;
521 srcShift = 8;
523 srcShift -= bitsPerUnit;
527 srcComplete:
529 if( dstAvailCo < 8 )
531 *reinterpret_cast< unsigned char * >( dstCo ) = ( dstByteCo << dstAvailCo );
532 ++dstCo;
534 if( dstAvailAl < 8 )
536 *reinterpret_cast< unsigned char * >( dstAl ) = ( dstByteAl << dstAvailAl );
537 ++dstAl;
540 colorDst.write( bufCo, dstCo - bufCo );
541 alphaDst.write( bufAl, dstAl - bufAl );
544 template< class C >
545 void
546 Helpers::separateAlpha( const unsigned char * row, size_t rowBytes, std::ostream & colorDst, size_t colorUnits, std::ostream & alphaDst, size_t alphaUnits, const png_color_16 * transparentColor, char * bufCo, char * bufAl )
548 C * dstCo = reinterpret_cast< C * >( bufCo );
549 C * dstAl = reinterpret_cast< C * >( bufAl );
551 C OPAQUE = 0;
553 png_uint_16 transparentColorArray[3];
554 if( transparentColor != 0 )
556 switch( colorUnits )
558 case 1:
559 transparentColorArray[0] = transparentColor->gray;
560 break;
561 case 3:
562 transparentColorArray[0] = transparentColor->red;
563 transparentColorArray[1] = transparentColor->green;
564 transparentColorArray[2] = transparentColor->blue;
565 break;
566 default:
567 throw Exceptions::InternalError( "Unexpected number of color channels in PNG image alpha bit separation." );
571 const C * src = reinterpret_cast< const C * >( row );
572 const C * srcEnd = reinterpret_cast< const C * >( row + rowBytes );
573 const C * tmpEnd = reinterpret_cast< const C * >( row );
574 for( ; src < srcEnd; )
576 bool trans = true;
577 const png_uint_16 * transparentColorSrc = transparentColorArray;
579 tmpEnd += colorUnits;
580 for( ; src != tmpEnd; ++src, ++dstCo, ++transparentColorSrc )
582 *reinterpret_cast< unsigned char * >( dstCo ) = *src;
583 if( transparentColor != 0 && *src != *transparentColorSrc )
585 trans = false;
588 tmpEnd += alphaUnits;
589 if( transparentColor == 0 )
591 for( ; src != tmpEnd; ++src, ++dstAl )
593 *reinterpret_cast< unsigned char * >( dstAl ) = *src;
596 else
598 *dstAl = trans ? (~OPAQUE) : OPAQUE;
599 ++dstAl;
601 /* Just ignore fill bytes. */
602 src = tmpEnd;
605 colorDst.write( bufCo, reinterpret_cast< char * >( dstCo ) - bufCo );
606 alphaDst.write( bufAl, reinterpret_cast< char * >( dstAl ) - bufAl );
609 void
610 Helpers::applyPalette( const unsigned char * row, size_t rowBytes, size_t index_depth, const png_colorp palette, const png_bytep trans, int num_palette, std::ostream & colorDst, std::ostream & alphaDst )
612 switch( index_depth )
614 case 1:
615 case 2:
616 case 4:
618 const unsigned char * src = row;
619 const unsigned char * srcEnd = row + rowBytes;
620 unsigned char srcByte = *src;
621 ++src;
622 unsigned char srcShift = 8 - index_depth;
623 unsigned char mask;
624 switch( index_depth )
626 case 1:
627 mask = 0x01;
628 break;
629 case 2:
630 mask = 0x03;
631 break;
632 case 4:
633 mask = 0x07;
634 break;
635 default:
636 throw Exceptions::InternalError( "Switch in PNG palette application was out of range." );
638 while( true )
640 unsigned char index = ( srcByte >> srcShift ) & mask;
641 if( index >= num_palette )
643 throw Exceptions::ExternalError( "PNG palette index is out of bounds." );
645 unsigned char buf[3];
646 buf[0] = palette[ index ].red;
647 buf[1] = palette[ index ].green;
648 buf[2] = palette[ index ].blue;
649 colorDst.write( reinterpret_cast< char * >( buf ), 3 );
650 if( trans != 0 )
652 alphaDst.write( reinterpret_cast< char * >( & ( trans[ index ] ) ), 1 );
654 if( srcShift == 0 )
656 if( src == srcEnd )
658 break;
660 srcByte = *src;
661 ++src;
662 srcShift = 8;
664 srcShift -= index_depth;
667 break;
668 case 8:
670 const unsigned char * srcEnd = row + rowBytes;
671 for( const unsigned char * src = row; src != srcEnd; ++src )
673 if( *src >= num_palette )
675 throw Exceptions::ExternalError( "PNG palette index is out of bounds." );
677 unsigned char buf[3];
678 buf[0] = palette[ *src ].red;
679 buf[1] = palette[ *src ].green;
680 buf[2] = palette[ *src ].blue;
681 colorDst.write( reinterpret_cast< char * >( buf ), 3 );
682 if( trans != 0 )
684 alphaDst.write( reinterpret_cast< char * >( & ( trans[ *src ] ) ), 1 );
688 break;
689 default:
690 throw Exceptions::InternalError( "Unexpected depth in PNG palette image (supported values are { 1, 2, 4, 8 })." );
694 #endif