fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Image / FileIO / OSGPNGImageFileType.cpp
blob7e63782ae0da4d8f81cf889035158fd01f38bff8
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //-------------------------------
40 // Includes
41 //-------------------------------
43 #include <cstdlib>
44 #include <cstdio>
46 #include "OSGConfig.h"
48 #ifdef OSG_SGI_LIB
49 #include <limits>
50 #endif
51 #ifdef OSG_WITH_PNG
52 #include <png.h>
53 #endif
55 #include "OSGPNGImageFileType.h"
56 #include "OSGLog.h"
58 #ifndef OSG_DO_DOC
59 # ifdef OSG_WITH_PNG
60 # define OSG_PNG_ARG(ARG) ARG
61 # else
62 # define OSG_PNG_ARG(ARG)
63 # endif
64 #else
65 # define OSG_PNG_ARG(ARG) ARG
66 #endif
68 static const OSG::Char8 *suffixArray[] =
70 "png"
73 OSG_BEGIN_NAMESPACE
75 /*! \class PNGImageFileType
77 Image File Type to read/write and store/restore Image objects as
78 PNG data.
80 To be able to load PNG images you need the PNG library,
81 (check the Prerequisites page on www.opensg.org).
82 The lib comes with all Linux distributions.
84 You have to --enable-png in the configure line to enable
85 the singleton object.
89 #ifdef OSG_WITH_PNG
91 static void isReadFunc(png_structp png_ptr, png_bytep data, png_size_t length)
93 std::istream *is =
94 reinterpret_cast<std::istream*>(png_get_io_ptr(png_ptr));
96 is->read(reinterpret_cast<char*>(data), length);
98 if(png_size_t(is->gcount()) != length)
99 png_error(png_ptr, "Cannot read from input stream");
102 static void osWriteFunc(png_structp png_ptr, png_bytep data, png_size_t length)
104 std::ostream *os =
105 reinterpret_cast<std::ostream*>(png_get_io_ptr(png_ptr));
107 os->write(reinterpret_cast<char*>(data), length);
109 if(os->good() == false)
110 png_error(png_ptr, "Cannot write to output stream");
113 static void osFlushFunc(png_structp png_ptr)
115 std::ostream *os =
116 reinterpret_cast<std::ostream*>(png_get_io_ptr(png_ptr));
118 os->flush();
120 if(os->good() == false)
121 png_error(png_ptr, "Cannot flush output stream");
124 static void errorOutput (png_structp png_ptr, const char *message)
126 FFATAL (("PNG: %s\n", message ));
128 longjmp(png_jmpbuf(png_ptr), 1);
131 static void warningOutput (png_structp OSG_CHECK_ARG(png_ptr),
132 const char *message)
134 FWARNING (("PNG: %s\n", message ));
137 #endif
139 PNGImageFileType PNGImageFileType:: _the("image/png",
140 suffixArray, sizeof(suffixArray),
141 (OSG_READ_SUPPORTED |
142 OSG_WRITE_SUPPORTED));
144 //-------------------------------------------------------------------------
145 /*! Tries to fill the image object with the data read from
146 the given stream. Returns true on success.
149 bool PNGImageFileType::read( Image *OSG_PNG_ARG(pImage ),
150 std::istream &OSG_PNG_ARG(is ),
151 const std::string &OSG_PNG_ARG(mimetype))
153 #ifdef OSG_WITH_PNG
155 bool retCode;
156 Image::PixelFormat pixelFormat = OSG::Image::OSG_INVALID_PF;
157 png_structp png_ptr;
158 png_infop info_ptr;
159 png_uint_32 width, wc, height, h, i, res_x, res_y;
160 png_byte bit_depth, channels, color_type;
161 png_bytep *row_pointers, base;
163 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
165 if(!png_ptr)
166 return false;
168 png_set_error_fn(png_ptr, 0, &errorOutput, &warningOutput);
170 info_ptr = png_create_info_struct(png_ptr);
172 if(!info_ptr)
174 png_destroy_read_struct(&png_ptr, 0, 0);
175 return false;
178 if(setjmp(png_jmpbuf(png_ptr)))
180 png_destroy_read_struct(&png_ptr, &info_ptr, 0);
181 return false;
184 png_set_read_fn(png_ptr, &is, &isReadFunc);
186 png_read_info(png_ptr, info_ptr);
188 width = png_get_image_width(png_ptr, info_ptr);
189 height = png_get_image_height(png_ptr, info_ptr);
190 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
191 res_x = png_get_x_pixels_per_meter(png_ptr, info_ptr);
192 res_y = png_get_y_pixels_per_meter(png_ptr, info_ptr);
193 channels = png_get_channels(png_ptr, info_ptr);
194 color_type = png_get_color_type(png_ptr, info_ptr);
196 // Convert paletted images to RGB
197 if (color_type == PNG_COLOR_TYPE_PALETTE)
199 png_set_palette_to_rgb(png_ptr);
200 channels = 3;
201 bit_depth = 8;
204 // Convert < 8 bit to 8 bit
205 if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
207 png_set_expand_gray_1_2_4_to_8(png_ptr);
208 bit_depth = 8;
211 #if BYTE_ORDER == LITTLE_ENDIAN
212 if (bit_depth == 16)
213 png_set_swap(png_ptr);
214 #endif
216 // Add a full alpha channel if there is transparency
217 // information in a tRNS chunk
218 if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
220 png_set_tRNS_to_alpha(png_ptr);
221 ++channels;
224 Int32 dataType;
226 switch (bit_depth)
228 case 8:
229 dataType = Image::OSG_UINT8_IMAGEDATA;
230 break;
231 case 16:
232 dataType = Image::OSG_UINT16_IMAGEDATA;
233 break;
234 default:
235 FWARNING (( "Invalid bit_depth: %d, can not read png-data\n",
236 bit_depth ));
237 return false;
240 switch(channels)
242 case 1:
243 pixelFormat = Image::OSG_L_PF;
244 break;
245 case 2:
246 pixelFormat = Image::OSG_LA_PF;
247 break;
248 case 3:
249 pixelFormat = Image::OSG_RGB_PF;
250 break;
251 case 4:
252 pixelFormat = Image::OSG_RGBA_PF;
253 break;
256 if(pImage->set(pixelFormat, width, height,
257 1, 1, 1, 0.0, 0,
258 dataType))
260 // set resolution png supports only pixel per meter,
261 // so we do a conversion to dpi with some rounding.
262 res_x = png_uint_32((Real32(res_x) / 39.37007874f) < 0.0f ?
263 (Real32(res_x) / 39.37007874f) - 0.5f :
264 (Real32(res_x) / 39.37007874f) + 0.5f);
265 res_y = png_uint_32((Real32(res_y) / 39.37007874f) < 0.0f ?
266 (Real32(res_y) / 39.37007874f) - 0.5f :
267 (Real32(res_y) / 39.37007874f) + 0.5f);
269 pImage->setResX(Real32(res_x));
270 pImage->setResY(Real32(res_y));
271 pImage->setResUnit(Image::OSG_RESUNIT_INCH);
273 // Calculate the row pointers
274 row_pointers = new png_bytep[height];
275 wc = width * channels * (bit_depth / 8);
276 h = height - 1;
277 base = pImage->editData();
279 for(i = 0; i < height; ++i)
280 row_pointers[i] = base + (h - i) * wc;
282 // Read the image data
283 png_read_image(png_ptr, row_pointers);
285 delete[] row_pointers;
287 retCode = true;
289 else
291 retCode = false;
294 png_destroy_read_struct(&png_ptr, &info_ptr, 0);
296 return retCode;
298 #else
300 SWARNING << getMimeType()
301 << " read is not compiled into the current binary "
302 << std::endl;
304 return false;
306 #endif
310 //-------------------------------------------------------------------------
311 /*! Tries to write the image object to the given fileName.
312 Returns true on success. Based on the public domain example.c
313 from the PNG dist.
316 bool PNGImageFileType::write(const Image *OSG_PNG_ARG(pImage ),
317 std::ostream &OSG_PNG_ARG(os ),
318 const std::string &OSG_PNG_ARG(mimetype))
320 #ifdef OSG_WITH_PNG
322 png_structp png_ptr;
323 png_infop info_ptr;
325 if(pImage->getDimension() < 1 || pImage->getDimension() > 2)
327 FWARNING(("PNGImageFileType::write: invalid dimension %d!\n",
328 pImage->getDimension()));
330 return false;
333 /* Create and initialize the png_struct with the desired error handler
334 * functions. If you want to use the default stderr and longjump method,
335 * you can supply NULL for the last three parameters. We also check that
336 * the library version is compatible with the one used at compile time,
337 * in case we are using dynamically linked libraries. REQUIRED.
339 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
340 0, &errorOutput, &warningOutput);
342 if(png_ptr == NULL)
343 return false;
345 /* Allocate/initialize the image information data. REQUIRED */
346 info_ptr = png_create_info_struct(png_ptr);
348 if(info_ptr == NULL)
350 png_destroy_write_struct(&png_ptr, NULL);
351 return false;
354 /* set up the output handlers */
355 png_set_write_fn(png_ptr, &os, &osWriteFunc, &osFlushFunc);
357 /* This is the hard way */
359 /* Set the image information here. Width and height are up to 2^31,
360 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
361 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
362 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
363 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
364 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
365 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
368 Int32 ctype;
369 switch(pImage->getPixelFormat())
371 case Image::OSG_L_PF:
372 ctype = PNG_COLOR_TYPE_GRAY;
373 break;
375 case Image::OSG_LA_PF:
376 ctype = PNG_COLOR_TYPE_GRAY_ALPHA;
377 break;
379 #if defined(GL_BGR) || defined(GL_BGR_EXT)
380 case Image::OSG_BGR_PF:
381 #endif
382 case Image::OSG_RGB_PF:
383 ctype = PNG_COLOR_TYPE_RGB;
384 break;
386 #if defined(GL_BGRA) || defined(GL_BGRA_EXT)
387 case Image::OSG_BGRA_PF:
388 #endif
389 case Image::OSG_RGBA_PF:
390 ctype = PNG_COLOR_TYPE_RGB_ALPHA;
391 break;
393 default:
394 FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n",
395 pImage->getPixelFormat()));
396 png_destroy_write_struct(&png_ptr, NULL);
397 return false;
401 Int32 bit_depth;
402 switch(pImage->getDataType())
404 case Image::OSG_UINT8_IMAGEDATA:
405 bit_depth = 8;
406 break;
407 case Image::OSG_UINT16_IMAGEDATA:
408 bit_depth = 16;
409 break;
410 default:
411 FWARNING (("Invalid pixeldepth, cannot store data\n"));
412 return false;
415 png_set_IHDR(png_ptr, info_ptr, pImage->getWidth(), pImage->getHeight(),
416 bit_depth,ctype,
417 PNG_INTERLACE_NONE,
418 PNG_COMPRESSION_TYPE_BASE,
419 PNG_FILTER_TYPE_BASE);
421 // set resolution png supports only meter per pixel,
422 // so we do a conversion from dpi with some rounding.
423 png_uint_32 res_x = png_uint_32(pImage->getResX());
424 png_uint_32 res_y = png_uint_32(pImage->getResY());
425 if(pImage->getResUnit() == Image::OSG_RESUNIT_INCH)
427 res_x = png_uint_32((pImage->getResX() * 39.37007874f) < 0.0f ?
428 (pImage->getResX() * 39.37007874f) - 0.5f :
429 (pImage->getResX() * 39.37007874f) + 0.5f);
430 res_y = png_uint_32((pImage->getResY() * 39.37007874f) < 0.0f ?
431 (pImage->getResY() * 39.37007874f) - 0.5f :
432 (pImage->getResY() * 39.37007874f) + 0.5f);
435 png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
436 PNG_RESOLUTION_METER);
438 #if 0
439 /* optional significant bit chunk */
440 /* if we are dealing with a grayscale image then */
441 sig_bit.gray = true_bit_depth;
442 /* otherwise, if we are dealing with a color image then */
443 sig_bit.red = true_red_bit_depth;
444 sig_bit.green = true_green_bit_depth;
445 sig_bit.blue = true_blue_bit_depth;
446 /* if the image has an alpha channel then */
447 sig_bit.alpha = true_alpha_bit_depth;
448 png_set_sBIT(png_ptr, info_ptr, sig_bit);
451 /* Optional gamma chunk is strongly suggested if you have any guess
452 * as to the correct gamma of the image.
454 png_set_gAMA(png_ptr, info_ptr, gamma);
456 /* Optionally write comments into the image */
457 text_ptr[0].key = "Title";
458 text_ptr[0].text = "Mona Lisa";
459 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
460 text_ptr[1].key = "Author";
461 text_ptr[1].text = "Leonardo DaVinci";
462 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
463 text_ptr[2].key = "Description";
464 text_ptr[2].text = "<long text>";
465 text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
466 #ifdef PNG_iTXt_SUPPORTED
467 text_ptr[0].lang = NULL;
468 text_ptr[1].lang = NULL;
469 text_ptr[2].lang = NULL;
470 #endif
471 png_set_text(png_ptr, info_ptr, text_ptr, 3);
472 #endif
473 /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
474 /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
475 * on read and must be written in accordance with the sRGB profile */
477 /* Write the file header information. REQUIRED */
478 png_write_info(png_ptr, info_ptr);
480 #if BYTE_ORDER == LITTLE_ENDIAN
481 if (bit_depth == 16)
482 png_set_swap(png_ptr);
483 #endif
485 #if 0
486 /* invert monochrome pixels */
487 png_set_invert_mono(png_ptr);
489 /* Shift the pixels up to a legal bit depth and fill in
490 * as appropriate to correctly scale the image.
492 png_set_shift(png_ptr, &sig_bit);
494 /* pack pixels into bytes */
495 png_set_packing(png_ptr);
497 /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
498 * RGB (4 channels -> 3 channels). The second parameter is not used.
500 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
502 /* swap bytes of 16-bit files to most significant byte first */
503 png_set_swap(png_ptr);
505 /* swap bits of 1, 2, 4 bit packed pixel formats */
506 png_set_packswap(png_ptr);
507 #endif
509 if(pImage->getPixelFormat() == Image::OSG_BGR_PF ||
510 pImage->getPixelFormat() == Image::OSG_BGRA_PF )
512 /* flip BGR pixels to RGB */
513 png_set_bgr(png_ptr);
515 /* swap location of alpha bytes from ARGB to RGBA */
516 png_set_swap_alpha(png_ptr);
519 /* The easiest way to write the image (you may have a different memory
520 * layout, however, so choose what fits your needs best). You need to
521 * use the first method if you aren't handling interlacing yourself.
523 png_bytep *row_pointers = new png_bytep [pImage->getHeight()];
525 for(Int32 k = 0; k < pImage->getHeight(); k++)
527 row_pointers[k] =
528 (const_cast<UInt8 *>(pImage->getData())) +
529 (pImage->getHeight() - 1 - k) *
530 pImage->getWidth() * pImage->getBpp();
533 /* write out the entire image data in one call */
534 png_write_image(png_ptr, row_pointers);
536 /* It is REQUIRED to call this to finish writing the rest of the file */
537 png_write_end(png_ptr, info_ptr);
539 /* clean up after the write, and free any memory allocated */
540 png_destroy_write_struct(&png_ptr, &info_ptr);
542 delete [] row_pointers;
544 /* that's it */
545 return true;
547 #else
548 SWARNING << getMimeType()
549 << " write is not compiled into the current binary "
550 << endLog;
552 return false;
553 #endif
557 //-------------------------------------------------------------------------
559 Tries to determine the mime type of the data provided by an input stream
560 by searching for magic bytes. Returns the mime type or an empty string
561 when the function could not determine the mime type.
563 std::string PNGImageFileType::determineMimetypeFromStream(std::istream &is)
565 char filecode[4];
566 is.read(filecode, 4);
567 is.seekg(-4, std::ios::cur);
569 return strncmp(filecode, "\x89PNG", 4) == 0 ?
570 std::string(getMimeType()) : std::string();
575 bool PNGImageFileType::validateHeader(const Char8 *fileName, bool &implemented)
577 implemented = true;
579 if(fileName == NULL)
580 return false;
582 FILE *file = fopen(fileName, "rb");
584 if(file == NULL)
585 return false;
587 std::string magic;
589 magic.resize(4);
591 fread(static_cast<void *>(&magic[0]), 4, 1, file);
593 fclose(file);
595 if(magic == "\x89PNG")
597 return true;
600 return false;
603 #ifdef OSG_WITH_PNG
604 typedef struct
606 UChar8 *buffer;
607 UInt64 length;
608 } BufferInfo;
610 static void user_read_data(png_structp png_ptr,
611 png_bytep data, png_size_t length)
613 BufferInfo *bufferInfo = static_cast<BufferInfo *>(png_get_io_ptr(png_ptr));
614 memcpy(static_cast<void *>(data),
615 static_cast<void *>(bufferInfo->buffer),
616 length);
617 bufferInfo->buffer += length;
618 bufferInfo->length += length;
620 #endif
622 /* */
623 UInt64 PNGImageFileType::restoreData( Image *OSG_PNG_ARG (pImage ),
624 const UChar8 *OSG_PNG_ARG (buffer ),
625 Int32 OSG_CHECK_ARG(memSize)) const
627 #ifdef OSG_WITH_PNG
629 UInt64 retCode;
630 Image::PixelFormat pixelFormat = Image::OSG_INVALID_PF;
631 png_structp png_ptr;
632 png_infop info_ptr;
633 png_uint_32 width, wc, height, h, i;
634 png_byte bit_depth, channels, color_type;
635 png_bytep *row_pointers, base;
637 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
639 if(!png_ptr)
641 return 0;
644 png_set_error_fn(png_ptr, 0, &errorOutput, &warningOutput);
646 info_ptr = png_create_info_struct(png_ptr);
648 if(!info_ptr)
650 png_destroy_read_struct(&png_ptr, 0, 0);
651 return 0;
654 if(setjmp(png_jmpbuf(png_ptr)))
656 png_destroy_read_struct(&png_ptr, &info_ptr, 0);
657 return 0;
660 BufferInfo bufferInfo;
661 bufferInfo.buffer = const_cast<UChar8 *>(buffer);
662 bufferInfo.length = 0;
663 png_set_read_fn(png_ptr, static_cast<void *>(&bufferInfo), user_read_data);
665 png_read_info(png_ptr, info_ptr);
667 width = png_get_image_width(png_ptr, info_ptr);
668 height = png_get_image_height(png_ptr, info_ptr);
669 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
670 channels = png_get_channels(png_ptr, info_ptr);
671 color_type = png_get_color_type(png_ptr, info_ptr);
673 // Convert paletted images to RGB
674 if(color_type == PNG_COLOR_TYPE_PALETTE)
676 png_set_palette_to_rgb(png_ptr);
677 channels = 3;
678 bit_depth = 8;
681 // Convert < 8 bit to 8 bit
682 if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
684 png_set_expand_gray_1_2_4_to_8(png_ptr);
685 bit_depth = 8;
688 #if BYTE_ORDER == LITTLE_ENDIAN
689 if (bit_depth == 16)
690 png_set_swap(png_ptr);
691 #endif
693 // Add a full alpha channel if there is transparency
694 // information in a tRNS chunk
695 if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
697 png_set_tRNS_to_alpha(png_ptr);
698 ++channels;
701 Int32 dataType;
703 switch (bit_depth)
705 case 8:
706 dataType = Image::OSG_UINT8_IMAGEDATA;
707 break;
708 case 16:
709 dataType = Image::OSG_UINT16_IMAGEDATA;
710 break;
711 default:
712 FWARNING (( "Invalid bit_depth: %d, can not read png-data\n",
713 bit_depth ));
714 return false;
717 switch(channels)
719 case 1:
720 pixelFormat = Image::OSG_L_PF;
721 break;
722 case 2:
723 pixelFormat = Image::OSG_LA_PF;
724 break;
725 case 3:
726 pixelFormat = Image::OSG_RGB_PF;
727 break;
728 case 4:
729 pixelFormat = Image::OSG_RGBA_PF;
730 break;
733 if(pImage->set(pixelFormat, width, height,
734 1, 1, 1, 0.0, 0,
735 dataType))
737 // Calculate the row pointers
738 row_pointers = new png_bytep[height];
739 wc = width * channels * (bit_depth / 8);
740 h = height - 1;
741 base = pImage->editData();
743 for(i = 0; i < height; ++i)
744 row_pointers[i] = base + (h - i) * wc;
746 // Read the image data
747 png_read_image(png_ptr, row_pointers);
749 delete[] row_pointers;
751 retCode = bufferInfo.length;
753 else
755 retCode = 0;
758 png_destroy_read_struct(&png_ptr, &info_ptr, 0);
760 return retCode;
762 #else
763 SWARNING << getMimeType()
764 << " restoreData is not compiled into the current binary "
765 << std::endl;
767 return 0;
768 #endif
771 #ifdef OSG_WITH_PNG
773 static void user_write_data(png_structp png_ptr,
774 png_bytep data, png_size_t length)
776 BufferInfo *bufferInfo = static_cast<BufferInfo *>(png_get_io_ptr(png_ptr));
777 memcpy(static_cast<void *>(bufferInfo->buffer),
778 static_cast<void *>(data),
779 length);
780 bufferInfo->buffer += length;
781 bufferInfo->length += length;
784 static void user_flush_data(png_structp OSG_CHECK_ARG(png_ptr))
788 #endif
790 //-------------------------------------------------------------------------
791 /*! Tries to restore the image data from the given memblock.
792 Returns the amount of data read.
795 UInt64 PNGImageFileType::storeData(const Image *OSG_PNG_ARG (pImage ),
796 UChar8 *OSG_PNG_ARG (buffer ),
797 Int32 OSG_CHECK_ARG(memSize)) const
799 #ifdef OSG_WITH_PNG
801 png_structp png_ptr;
802 png_infop info_ptr;
804 if(pImage->getDimension() < 1 || pImage->getDimension() > 2)
806 FWARNING(("PNGImageFileType::write: invalid dimension %d!\n",
807 pImage->getDimension()));
808 return 0;
811 /* Create and initialize the png_struct with the desired error handler
812 * functions. If you want to use the default stderr and longjump method,
813 * you can supply NULL for the last three parameters. We also check that
814 * the library version is compatible with the one used at compile time,
815 * in case we are using dynamically linked libraries. REQUIRED.
818 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
819 0, &errorOutput, &warningOutput);
821 if (png_ptr == NULL)
823 return 0;
826 /* Allocate/initialize the image information data. REQUIRED */
827 info_ptr = png_create_info_struct(png_ptr);
829 if(info_ptr == NULL)
831 png_destroy_write_struct(&png_ptr, NULL);
832 return 0;
835 BufferInfo bufferInfo;
836 bufferInfo.buffer = buffer;
837 bufferInfo.length = 0;
839 png_set_write_fn(png_ptr,
840 static_cast<void *>(&bufferInfo),
841 user_write_data,
842 user_flush_data);
844 /* This is the hard way */
846 /* Set the image information here. Width and height are up to 2^31,
847 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
848 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
849 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
850 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
851 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
852 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
855 Int32 ctype;
856 switch(pImage->getPixelFormat())
858 case Image::OSG_L_PF:
859 ctype = PNG_COLOR_TYPE_GRAY;
860 break;
862 case Image::OSG_LA_PF:
863 ctype = PNG_COLOR_TYPE_GRAY_ALPHA;
864 break;
866 #if defined(GL_BGR) || defined(GL_BGR_EXT)
867 case Image::OSG_BGR_PF:
868 #endif
869 case Image::OSG_RGB_PF:
870 ctype = PNG_COLOR_TYPE_RGB;
871 break;
873 #if defined(GL_BGRA) || defined(GL_BGRA_EXT)
874 case Image::OSG_BGRA_PF:
875 #endif
876 case Image::OSG_RGBA_PF:
877 ctype = PNG_COLOR_TYPE_RGB_ALPHA;
878 break;
880 default:
881 FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n",
882 pImage->getPixelFormat()));
883 png_destroy_write_struct(&png_ptr, NULL);
885 return 0;
888 Int32 bit_depth;
890 switch (pImage->getDataType())
892 case Image::OSG_UINT8_IMAGEDATA:
893 bit_depth = 8;
894 break;
895 case Image::OSG_UINT16_IMAGEDATA:
896 bit_depth = 16;
897 break;
898 default:
899 FWARNING (("Invalid pixeldepth, cannot store data\n"));
900 return 0;
903 png_set_IHDR(png_ptr,
904 info_ptr,
905 pImage->getWidth(),
906 pImage->getHeight(),
907 bit_depth,
908 ctype,
909 PNG_INTERLACE_NONE,
910 PNG_COMPRESSION_TYPE_BASE,
911 PNG_FILTER_TYPE_BASE);
913 /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
914 /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
915 * on read and must be written in accordance with the sRGB profile */
917 /* Write the file header information. REQUIRED */
919 png_write_info(png_ptr, info_ptr);
921 #if BYTE_ORDER == LITTLE_ENDIAN
922 if (bit_depth == 16)
923 png_set_swap(png_ptr);
924 #endif
926 if(pImage->getPixelFormat() == Image::OSG_BGR_PF ||
927 pImage->getPixelFormat() == Image::OSG_BGRA_PF)
929 /* flip BGR pixels to RGB */
930 png_set_bgr(png_ptr);
932 /* swap location of alpha bytes from ARGB to RGBA */
933 png_set_swap_alpha(png_ptr);
936 /* The easiest way to write the image (you may have a different memory
937 * layout, however, so choose what fits your needs best). You need to
938 * use the first method if you aren't handling interlacing yourself.
941 png_bytep *row_pointers = new png_bytep [pImage->getHeight()];
943 for(Int32 k = 0; k < pImage->getHeight(); k++)
945 row_pointers[k] =
946 (const_cast<UInt8 *>(pImage->getData())) +
947 (pImage->getHeight() - 1 - k) *
948 pImage->getWidth() * pImage->getBpp();
951 /* write out the entire image data in one call */
952 png_write_image(png_ptr, row_pointers);
954 /* It is REQUIRED to call this to finish writing the rest of the file */
955 png_write_end(png_ptr, info_ptr);
957 /* clean up after the write, and free any memory allocated */
958 png_destroy_write_struct(&png_ptr, &info_ptr);
960 delete [] row_pointers;
962 /* that's it */
963 return bufferInfo.length;
964 #else
965 SWARNING << getMimeType()
966 << " storeData is not compiled into the current binary "
967 << std::endl;
969 return 0;
970 #endif
973 const PNGImageFileType &PNGImageFileType::the(void)
975 return _the;
978 //-------------------------------------------------------------------------
979 /*! Constructor used for the singleton object
982 PNGImageFileType::PNGImageFileType(const Char8 *mimeType,
983 const Char8 *suffixArray[],
984 UInt16 suffixByteCount,
985 UInt32 flags ) :
987 Inherited(mimeType, suffixArray, suffixByteCount, flags)
992 //-------------------------------------------------------------------------
993 /*! Destructor
996 PNGImageFileType::~PNGImageFileType(void)
1000 OSG_END_NAMESPACE