1 /************************************************************************/
2 /*                                                                      */
3 /*               Copyright 2001-2002 by Gunnar Kedenburg                */
4 /*       Cognitive Systems Group, University of Hamburg, Germany        */
5 /*                                                                      */
6 /*    This file is part of the VIGRA computer vision library.           */
7 /*    ( Version 1.5.0, Dec 07 2006 )                                    */
8 /*    The VIGRA Website is                                              */
9 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
10 /*    Please direct questions, bug reports, and contributions to        */
11 /*        koethe@informatik.uni-hamburg.de          or                  */
12 /*        vigra@kogs1.informatik.uni-hamburg.de                         */
13 /*                                                                      */
14 /*    Permission is hereby granted, free of charge, to any person       */
15 /*    obtaining a copy of this software and associated documentation    */
16 /*    files (the "Software"), to deal in the Software without           */
17 /*    restriction, including without limitation the rights to use,      */
18 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
19 /*    sell copies of the Software, and to permit persons to whom the    */
20 /*    Software is furnished to do so, subject to the following          */
21 /*    conditions:                                                       */
22 /*                                                                      */
23 /*    The above copyright notice and this permission notice shall be    */
24 /*    included in all copies or substantial portions of the             */
25 /*    Software.                                                         */
26 /*                                                                      */
27 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
28 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
29 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
30 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
31 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
32 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
33 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
34 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
35 /*                                                                      */
36 /************************************************************************/
37 /* Modifications by Pablo d'Angelo
38  * updated to vigra 1.4 by Douglas Wilkins
39  * as of 18 Febuary 2006:
40  *  - Changed INT16 -> UINT16 pixel type.
41  *  - Added support for obtaining extra bands beyond RGB.
42  *  - Added support for a position field that indicates the start of this
43  *    image relative to some global origin.
44  *  - Added support for x and y resolution fields.
45  */
46 
47 #ifdef HasPNG
48 
49 #include "vigra/config.hxx"
50 #include "vigra/sized_int.hxx"
51 #include "void_vector.hxx"
52 #include "auto_file.hxx"
53 #include "png.hxx"
54 #include "byteorder.hxx"
55 #include "error.hxx"
56 #include <stdexcept>
57 #include <iostream>
58 
59 extern "C"
60 {
61 #include <png.h>
62 }
63 
64 #if PNG_LIBPNG_VER < 10201
65 #error "please update your libpng to at least 1.2.1"
66 #endif
67 
68 // TODO: per-scanline reading/writing
69 
70 namespace {
71     std::string png_error_message;
72 }
73 
74 extern "C" {
75 
76 // called on fatal errors
PngError(png_structp png_ptr,png_const_charp error_msg)77 static void PngError( png_structp png_ptr, png_const_charp error_msg )
78 {
79     png_error_message = std::string(error_msg);
80     longjmp( png_ptr->jmpbuf, 1 );
81 }
82 
83 // called on non-fatal errors
PngWarning(png_structp,png_const_charp warning_msg)84 static void PngWarning( png_structp, png_const_charp warning_msg )
85 {
86     std::cerr << warning_msg << std::endl;
87 }
88 
89 } // extern "C"
90 
91 namespace vigra {
92 
getCodecDesc() const93     CodecDesc PngCodecFactory::getCodecDesc() const
94     {
95         CodecDesc desc;
96 
97         // init file type
98         desc.fileType = "PNG";
99 
100         // init pixel types
101         desc.pixelTypes.resize(2);
102         desc.pixelTypes[0] = "UINT8";
103         desc.pixelTypes[1] = "UINT16";
104 
105         // init compression types
106         desc.compressionTypes.resize(1);
107         desc.compressionTypes[0] = "LOSSLESS";
108 
109         // init magic strings
110         desc.magicStrings.resize(1);
111         desc.magicStrings[0].resize(4);
112         desc.magicStrings[0][0] = '\x89';
113         desc.magicStrings[0][1] = 'P';
114         desc.magicStrings[0][2] = 'N';
115         desc.magicStrings[0][3] = 'G';
116 
117         // init file extensions
118         desc.fileExtensions.resize(1);
119         desc.fileExtensions[0] = "png";
120 
121         desc.bandNumbers.resize(4);
122         desc.bandNumbers[0] = 1;
123         desc.bandNumbers[1] = 2;
124         desc.bandNumbers[2] = 3;
125         desc.bandNumbers[3] = 4;
126 
127         return desc;
128     }
129 
getDecoder() const130     std::auto_ptr<Decoder> PngCodecFactory::getDecoder() const
131     {
132         return std::auto_ptr<Decoder>( new PngDecoder() );
133     }
134 
getEncoder() const135     std::auto_ptr<Encoder> PngCodecFactory::getEncoder() const
136     {
137         return std::auto_ptr<Encoder>( new PngEncoder() );
138     }
139 
140     struct PngDecoderImpl
141     {
142         // data source
143         auto_file file;
144 
145         // data container
146         void_vector_base bands;
147 
148         // this is where libpng stores its state
149         png_structp png;
150         png_infop info;
151 
152         // image header fields
153         png_uint_32 width, height, components;
154         png_uint_32 extra_components;
155         Diff2D position;
156         int bit_depth, color_type;
157 
158         // icc profile, if available
159         // the memory is owned by libpng
160         UInt32 iccProfileLength;
161         const unsigned char *iccProfilePtr;
162 
163         // scanline counter
164         int scanline;
165 
166         float x_resolution, y_resolution;
167 
168         // number of passes needed during reading each scanline
169         int interlace_method, n_interlace_passes;
170 
171         // number of channels in png (or what libpng get_channels returns)
172         int n_channels;
173 
174         // size of one row
175         int rowsize;
176         void_vector<unsigned char> row_data;
177 
178         // ctor, dtor
179         PngDecoderImpl( const std::string & filename );
180         ~PngDecoderImpl();
181 
182         // methods
183         void init();
184         void nextScanline();
185     };
186 
PngDecoderImpl(const std::string & filename)187     PngDecoderImpl::PngDecoderImpl( const std::string & filename )
188 #ifdef VIGRA_NEED_BIN_STREAMS
189         // Returns the layer
190         : file( filename.c_str(), "rb" ),
191 #else
192         : file( filename.c_str(), "r" ),
193 #endif
194           bands(0), iccProfileLength(0), iccProfilePtr(0),
195           scanline(-1), x_resolution(0), y_resolution(0),
196           n_interlace_passes(0), n_channels(0)
197     {
198         png_error_message = "";
199         // check if the file is a png file
200         const unsigned int sig_size = 8;
201         png_byte sig[sig_size];
202         std::fread( sig, sig_size, 1, file.get() );
203         const int no_png = png_sig_cmp( sig, 0, sig_size );
204         vigra_precondition( !no_png, "given file is not a png file.");
205 
206         // create png read struct with user defined handlers
207         png = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL,
208                                       &PngError, &PngWarning );
209         vigra_postcondition( png != 0, "could not create the read struct." );
210 
211         // create info struct
212         if (setjmp(png->jmpbuf)) {
213             png_destroy_read_struct( &png, &info, NULL );
214             vigra_postcondition( false, png_error_message.insert(0, "error in png_create_info_struct(): ").c_str() );
215         }
216         info = png_create_info_struct(png);
217         vigra_postcondition( info != 0, "could not create the info struct." );
218 
219         // init png i/o
220         if (setjmp(png->jmpbuf)) {
221             png_destroy_read_struct( &png, &info, NULL );
222             vigra_postcondition( false, png_error_message.insert(0, "error in png_init_io(): ").c_str() );
223         }
224         png_init_io( png, file.get() );
225 
226         // specify that the signature was already read
227         if (setjmp(png->jmpbuf)) {
228             png_destroy_read_struct( &png, &info, NULL );
229             vigra_postcondition( false, png_error_message.insert(0, "error in png_set_sig_bytes(): ").c_str() );
230         }
231         png_set_sig_bytes( png, sig_size );
232 
233     }
234 
~PngDecoderImpl()235     PngDecoderImpl::~PngDecoderImpl()
236     {
237         png_destroy_read_struct( &png, &info, NULL );
238     }
239 
init()240     void PngDecoderImpl::init()
241     {
242         // read all chunks up to the image data
243         if (setjmp(png->jmpbuf))
244             vigra_postcondition( false, png_error_message.insert(0, "error in png_read_info(): ").c_str() );
245         png_read_info( png, info );
246 
247         // pull over the header fields
248         int interlace_method, compression_method, filter_method;
249         if (setjmp(png->jmpbuf))
250             vigra_postcondition( false, png_error_message.insert(0, "error in png_get_IHDR(): ").c_str() );
251         png_get_IHDR( png, info, &width, &height, &bit_depth, &color_type,
252                       &interlace_method, &compression_method, &filter_method );
253 
254         // check whether byteorder must be swapped (png files are big-endian)
255         byteorder bo;
256         if(bit_depth == 16 && bo.get_host_byteorder() == "little endian")
257         {
258             png_set_swap(png);
259         }
260 
261         // transform palette to rgb
262         if ( color_type == PNG_COLOR_TYPE_PALETTE) {
263             if (setjmp(png->jmpbuf))
264                 vigra_postcondition( false, png_error_message.insert(0, "error in png_palette_to_rgb(): ").c_str() );
265             png_set_palette_to_rgb(png);
266             color_type = PNG_COLOR_TYPE_RGB;
267             bit_depth = 8;
268         }
269 
270         // expand gray values to at least one byte size
271         if ( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 ) {
272             if (setjmp(png->jmpbuf))
273                 vigra_postcondition( false,png_error_message.insert(0, "error in png_set_gray_1_2_4_to_8(): ").c_str());
274             png_set_gray_1_2_4_to_8(png);
275             bit_depth = 8;
276         }
277 
278 
279 #if 0
280         // strip alpha channel
281         if ( color_type & PNG_COLOR_MASK_ALPHA ) {
282             if (setjmp(png->jmpbuf))
283                 vigra_postcondition( false, png_error_message.insert(0, "error in png_set_strip_alpha(): ").c_str() );
284             png_set_strip_alpha(png);
285             color_type ^= PNG_COLOR_MASK_ALPHA;
286         }
287 #endif /* #if 0 */
288 
289 
290         // find out the number of components
291         switch (color_type) {
292         case PNG_COLOR_TYPE_GRAY:
293             components = 1;
294             extra_components = 0;
295             break;
296         case PNG_COLOR_TYPE_GRAY_ALPHA:
297             components = 2;
298             extra_components = 1;
299             break;
300         case PNG_COLOR_TYPE_RGB:
301             components = 3;
302             extra_components = 0;
303             break;
304         case PNG_COLOR_TYPE_RGB_ALPHA:
305             components = 4;
306             extra_components = 1;
307             break;
308         default:
309             vigra_fail( "internal error: illegal color type." );
310         }
311 
312         // read resolution
313         x_resolution = png_get_x_pixels_per_meter( png, info ) / 254.0;
314         y_resolution = png_get_y_pixels_per_meter( png, info ) / 254.0;
315 
316         // read offset
317         position.x = png_get_x_offset_pixels( png, info );
318         position.y = png_get_y_offset_pixels( png, info );
319 
320         // read icc profile
321 #if (PNG_LIBPNG_VER > 10008) && defined(PNG_READ_iCCP_SUPPORTED)
322         char * dummyName;
323         int dummyCompType;
324         char * profilePtr;
325         png_uint_32 profileLen;
326         if (info->valid & PNG_INFO_iCCP) {
327             png_get_iCCP(png, info, &dummyName, &dummyCompType, &profilePtr, &profileLen) ;
328             iccProfilePtr = (unsigned char *) profilePtr;
329             iccProfileLength = profileLen;
330         }
331 #endif
332 
333 #if 0
334         // gamma correction changes the pixels, this is unwanted.
335 
336         // image gamma
337         double image_gamma = 0.45455;
338         if ( png_get_valid( png, info, PNG_INFO_gAMA ) ) {
339             if (setjmp(png->jmpbuf))
340                 vigra_postcondition( false, png_error_message.insert(0, "error in png_get_gAMA(): ").c_str() );
341             png_get_gAMA( png, info, &image_gamma );
342         }
343 
344         // screen gamma
345         double screen_gamma = 2.2;
346 
347         // set gamma correction
348         if (setjmp(png->jmpbuf))
349             vigra_postcondition( false, png_error_message.insert(0, "error in png_set_gamma(): ").c_str() );
350         png_set_gamma( png, screen_gamma, image_gamma );
351 #endif
352 
353         // interlace handling, get number of read passes needed
354         if (setjmp(png->jmpbuf))
355             vigra_postcondition( false,png_error_message.insert(0, "error in png_set_interlace_handling(): ").c_str());
356         n_interlace_passes = png_set_interlace_handling(png);
357 
358         // update png library state to reflect any changes that were made
359         if (setjmp(png->jmpbuf))
360             vigra_postcondition( false, png_error_message.insert(0, "error in png_read_update_info(): ").c_str() );
361         png_read_update_info( png, info );
362 
363         if (setjmp(png->jmpbuf))
364             vigra_postcondition( false,png_error_message.insert(0, "error in png_get_channels(): ").c_str());
365         n_channels = png_get_channels(png, info);
366 
367         if (setjmp(png->jmpbuf))
368             vigra_postcondition( false,png_error_message.insert(0, "error in png_get_rowbytes(): ").c_str());
369         rowsize = png_get_rowbytes(png, info);
370 
371         // allocate data buffers
372         row_data.resize(rowsize);
373     }
374 
nextScanline()375     void PngDecoderImpl::nextScanline()
376     {
377         for (int i=0; i < n_interlace_passes; i++) {
378         if (setjmp(png->jmpbuf))
379                 vigra_postcondition( false,png_error_message.insert(0, "error in png_read_row(): ").c_str());
380             png_read_row(png, row_data.begin(), NULL);
381         }
382     }
383 
init(const std::string & filename)384     void PngDecoder::init( const std::string & filename )
385     {
386         pimpl = new PngDecoderImpl(filename);
387         pimpl->init();
388         if(pimpl->iccProfileLength)
389         {
390             Decoder::ICCProfile iccData(
391                 pimpl->iccProfilePtr,
392                 pimpl->iccProfilePtr + pimpl->iccProfileLength);
393             iccProfile_.swap(iccData);
394         }
395     }
396 
~PngDecoder()397     PngDecoder::~PngDecoder()
398     {
399         delete pimpl;
400     }
401 
getFileType() const402     std::string PngDecoder::getFileType() const
403     {
404         return "PNG";
405     }
406 
getWidth() const407     unsigned int PngDecoder::getWidth() const
408     {
409         return pimpl->width;
410     }
411 
getHeight() const412     unsigned int PngDecoder::getHeight() const
413     {
414         return pimpl->height;
415     }
416 
getNumBands() const417     unsigned int PngDecoder::getNumBands() const
418     {
419         return pimpl->components;
420     }
421 
getNumExtraBands() const422     unsigned int PngDecoder::getNumExtraBands() const
423     {
424         return pimpl->extra_components;
425     }
426 
getXResolution() const427     float PngDecoder::getXResolution() const
428     {
429         return pimpl->x_resolution;
430     }
431 
getYResolution() const432     float PngDecoder::getYResolution() const
433     {
434         return pimpl->y_resolution;
435     }
436 
getPosition() const437     Diff2D PngDecoder::getPosition() const
438     {
439         return pimpl->position;
440     }
441 
getPixelType() const442     std::string PngDecoder::getPixelType() const
443     {
444         switch (pimpl->bit_depth) {
445         case 8:
446             return "UINT8";
447         case 16:
448             return "UINT16";
449         default:
450             vigra_fail( "internal error: illegal pixel type." );
451         }
452         return "";
453     }
454 
getOffset() const455     unsigned int PngDecoder::getOffset() const
456     {
457         return pimpl->components;
458     }
459 
currentScanlineOfBand(unsigned int band) const460     const void * PngDecoder::currentScanlineOfBand( unsigned int band ) const
461     {
462         switch (pimpl->bit_depth) {
463         case 8:
464             {
465                 return pimpl->row_data.begin() + band;
466             }
467         case 16:
468             {
469                 return pimpl->row_data.begin() + 2*band;
470             }
471         default:
472             vigra_fail( "internal error: illegal bit depth." );
473         }
474         return 0;
475     }
476 
nextScanline()477     void PngDecoder::nextScanline()
478     {
479         pimpl->nextScanline();
480     }
481 
close()482     void PngDecoder::close() {}
483 
abort()484     void PngDecoder::abort() {}
485 
486     struct PngEncoderImpl
487     {
488         // data sink
489         auto_file file;
490 
491         // data container
492         void_vector_base bands;
493 
494         // this is where libpng stores its state
495         png_structp png;
496         png_infop info;
497 
498         // image header fields
499         png_uint_32 width, height, components;
500         png_uint_32 extra_components;
501         int bit_depth, color_type;
502 
503         // icc profile, if available
504         Encoder::ICCProfile iccProfile;
505 
506         // scanline counter
507         int scanline;
508 
509         // state
510         bool finalized;
511 
512         // image layer position
513         Diff2D position;
514 
515         // resolution
516         float x_resolution, y_resolution;
517 
518         // ctor, dtor
519         PngEncoderImpl( const std::string & filename );
520         ~PngEncoderImpl();
521 
522         // methods
523         void finalize();
524         void write();
525     };
526 
PngEncoderImpl(const std::string & filename)527     PngEncoderImpl::PngEncoderImpl( const std::string & filename )
528 #ifdef VIGRA_NEED_BIN_STREAMS
529         : file( filename.c_str(), "wb" ),
530 #else
531         : file( filename.c_str(), "w" ),
532 #endif
533           bands(0),
534           scanline(0), finalized(false),
535           x_resolution(0), y_resolution(0)
536     {
537         png_error_message = "";
538         // create png struct with user defined handlers
539         png = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL,
540                                        &PngError, &PngWarning );
541         vigra_postcondition( png != 0, "could not create the write struct." );
542 
543         // create info struct
544         if (setjmp(png->jmpbuf)) {
545             png_destroy_write_struct( &png, &info );
546             vigra_postcondition( false, png_error_message.insert(0, "error in png_info_struct(): ").c_str() );
547         }
548         info = png_create_info_struct(png);
549         if ( !info ) {
550             png_destroy_write_struct( &png, &info );
551             vigra_postcondition( false, png_error_message.insert(0, "could not create the info struct.: ").c_str() );
552         }
553 
554         // init png i/o
555         if (setjmp(png->jmpbuf)) {
556             png_destroy_write_struct( &png, &info );
557             vigra_postcondition( false, png_error_message.insert(0, "error in png_init_io(): ").c_str() );
558         }
559         png_init_io( png, file.get() );
560     }
561 
~PngEncoderImpl()562     PngEncoderImpl::~PngEncoderImpl()
563     {
564         png_destroy_write_struct( &png, &info );
565     }
566 
finalize()567     void PngEncoderImpl::finalize()
568     {
569         // write the IHDR
570         if (setjmp(png->jmpbuf))
571             vigra_postcondition( false, png_error_message.insert(0, "error in png_set_IHDR(): ").c_str() );
572         png_set_IHDR( png, info, width, height, bit_depth, color_type,
573                       PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
574                       PNG_FILTER_TYPE_DEFAULT );
575 
576         // set resolution
577         if (x_resolution > 0 && y_resolution > 0) {
578             if (setjmp(png->jmpbuf))
579                 vigra_postcondition( false, png_error_message.insert(0, "error in png_set_pHYs(): ").c_str() );
580             png_set_pHYs(png, info, (png_uint_32) (x_resolution * 254 + 0.5),
581                          (png_uint_32) (y_resolution * 254 + 0.5),
582                          PNG_RESOLUTION_METER);
583         }
584 
585         // set offset
586         if (position.x > 0 && position.y > 0) {
587             if (setjmp(png->jmpbuf))
588                 vigra_postcondition( false, png_error_message.insert(0, "error in png_set_oFFs(): ").c_str() );
589             png_set_oFFs(png, info, position.x, position.y, PNG_OFFSET_PIXEL);
590         }
591 
592 #if (PNG_LIBPNG_VER > 10008) && defined(PNG_WRITE_iCCP_SUPPORTED)
593         // set icc profile
594         if (iccProfile.size() > 0) {
595             png_set_iCCP(png, info, "icc", 0,
596                          (char *)iccProfile.begin(), iccProfile.size());
597         }
598 #endif
599 
600         // write the info struct
601         if (setjmp(png->jmpbuf))
602             vigra_postcondition( false, png_error_message.insert(0, "error in png_write_info(): ").c_str() );
603         png_write_info( png, info );
604 
605         // prepare the bands
606         bands.resize( ( bit_depth >> 3 ) * width * components * height );
607 
608         // enter finalized state
609         finalized = true;
610     }
611 
write()612     void PngEncoderImpl::write()
613     {
614         // prepare row pointers
615         png_uint_32 row_stride = ( bit_depth >> 3 ) * width * components;
616         void_vector<png_byte *>  row_pointers(height);
617         typedef void_vector<png_byte> vector_type;
618         vector_type & cbands = static_cast< vector_type & >(bands);
619         png_byte * mover = cbands.data();
620         for( png_uint_32 i = 0; i < height; ++i ) {
621             row_pointers[i] = mover;
622             mover += row_stride;
623         }
624 
625         // check whether byteorder must be swapped (png files must be big-endian)
626         byteorder bo;
627         if(bit_depth == 16 && bo.get_host_byteorder() == "little endian")
628         {
629             png_set_swap(png);
630         }
631 
632         // write the whole image
633         if (setjmp(png->jmpbuf))
634             vigra_postcondition( false, png_error_message.insert(0, "error in png_write_image(): ").c_str() );
635         png_write_image( png, row_pointers.begin() );
636         if (setjmp(png->jmpbuf))
637             vigra_postcondition( false, png_error_message.insert(0, "error in png_write_end(): ").c_str() );
638         png_write_end(png, info);
639     }
640 
init(const std::string & filename)641     void PngEncoder::init( const std::string & filename )
642     {
643         pimpl = new PngEncoderImpl(filename);
644     }
645 
~PngEncoder()646     PngEncoder::~PngEncoder()
647     {
648         delete pimpl;
649     }
650 
getFileType() const651     std::string PngEncoder::getFileType() const
652     {
653         return "PNG";
654     }
655 
setWidth(unsigned int width)656     void PngEncoder::setWidth( unsigned int width )
657     {
658         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
659         pimpl->width = width;
660     }
661 
setHeight(unsigned int height)662     void PngEncoder::setHeight( unsigned int height )
663     {
664         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
665         pimpl->height = height;
666     }
667 
setNumBands(unsigned int bands)668     void PngEncoder::setNumBands( unsigned int bands )
669     {
670         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
671         if ( bands == 1 )
672             pimpl->color_type = PNG_COLOR_TYPE_GRAY;
673         else if ( bands == 2 )
674             pimpl->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
675         else if ( bands == 3 )
676             pimpl->color_type = PNG_COLOR_TYPE_RGB;
677         else if ( bands == 4 )
678             pimpl->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
679         else
680             vigra_fail( "internal error: number of components not supported." );
681         pimpl->components = bands;
682     }
683 
setCompressionType(const std::string & comp,int quality)684     void PngEncoder::setCompressionType( const std::string & comp,
685                                          int quality )
686     {
687         // nothing is settable => do nothing
688     }
689 
setPosition(const Diff2D & pos)690     void PngEncoder::setPosition( const Diff2D & pos )
691     {
692         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
693         pimpl->position = pos;
694     }
695 
setXResolution(float xres)696     void PngEncoder::setXResolution( float xres )
697     {
698         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
699         pimpl->x_resolution = xres;
700     }
701 
setYResolution(float yres)702     void PngEncoder::setYResolution( float yres )
703     {
704         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
705         pimpl->y_resolution = yres;
706     }
707 
setPixelType(const std::string & pixelType)708     void PngEncoder::setPixelType( const std::string & pixelType )
709     {
710         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
711         if ( pixelType == "UINT8" )
712             pimpl->bit_depth = 8;
713         else if ( pixelType == "UINT16" )
714             pimpl->bit_depth = 16;
715         else
716             vigra_fail( "internal error: pixeltype not supported." );
717     }
718 
getOffset() const719     unsigned int PngEncoder::getOffset() const
720     {
721         return pimpl->components;
722     }
723 
setICCProfile(const ICCProfile & data)724     void PngEncoder::setICCProfile(const ICCProfile & data)
725     {
726         pimpl->iccProfile = data;
727     }
728 
finalizeSettings()729     void PngEncoder::finalizeSettings()
730     {
731         VIGRA_IMPEX_FINALIZED(pimpl->finalized);
732         pimpl->finalize();
733     }
734 
currentScanlineOfBand(unsigned int band)735     void * PngEncoder::currentScanlineOfBand( unsigned int band )
736     {
737         const unsigned int index = pimpl->width * pimpl->components
738             * pimpl->scanline + band;
739         switch (pimpl->bit_depth) {
740         case 8:
741             {
742                 typedef void_vector< UInt8 > bands_type;
743                 bands_type & bands
744                     = static_cast< bands_type & >(pimpl->bands);
745                 return bands.data() + index;
746             }
747         case 16:
748             {
749                 typedef void_vector<Int16> bands_type;
750                 bands_type & bands
751                     = static_cast< bands_type & >(pimpl->bands);
752                 return bands.data() + index;
753             }
754         default:
755             vigra_fail( "internal error: illegal bit depth." );
756         }
757         return 0;
758     }
759 
nextScanline()760     void PngEncoder::nextScanline()
761     {
762         ++(pimpl->scanline);
763     }
764 
close()765     void PngEncoder::close()
766     {
767         pimpl->write();
768     }
769 
abort()770     void PngEncoder::abort() {}
771 }
772 
773 #endif // HasPNG
774