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