1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "CImageLoaderPNG.h"
\r
7 #include <png.h> // use system lib png
\r
10 #include "CReadFile.h"
\r
18 // PNG function for error handling
\r
19 static void png_cpexcept_error(png_structp png_ptr, png_const_charp msg)
\r
21 os::Printer::log("PNG fatal error", msg, ELL_ERROR);
\r
22 longjmp(png_jmpbuf(png_ptr), 1);
\r
25 // PNG function for warning handling
\r
26 static void png_cpexcept_warn(png_structp png_ptr, png_const_charp msg)
\r
28 os::Printer::log("PNG warning", msg, ELL_WARNING);
\r
31 // PNG function for file reading
\r
32 void PNGAPI user_read_data_fcn(png_structp png_ptr, png_bytep data, png_size_t length)
\r
36 // changed by zola {
\r
37 io::IReadFile* file=(io::IReadFile*)png_get_io_ptr(png_ptr);
\r
38 check=(png_size_t) file->read((void*)data, length);
\r
41 if (check != length)
\r
42 png_error(png_ptr, "Read Error");
\r
46 //! returns true if the file maybe is able to be loaded by this class
\r
47 //! based on the file extension (e.g. ".tga")
\r
48 bool CImageLoaderPng::isALoadableFileExtension(const io::path& filename) const
\r
50 return core::hasFileExtension ( filename, "png" );
\r
54 //! returns true if the file maybe is able to be loaded by this class
\r
55 bool CImageLoaderPng::isALoadableFileFormat(io::IReadFile* file) const
\r
61 // Read the first few bytes of the PNG file
\r
62 if (file->read(buffer, 8) != 8)
\r
65 // Check if it really is a PNG file
\r
66 return !png_sig_cmp(buffer, 0, 8);
\r
70 // load in the image data
\r
71 IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const
\r
76 //Used to point to image rows
\r
77 u8** RowPointers = 0;
\r
80 // Read the first few bytes of the PNG file
\r
81 if( file->read(buffer, 8) != 8 )
\r
83 os::Printer::log("LOAD PNG: can't read file\n", file->getFileName(), ELL_ERROR);
\r
87 // Check if it really is a PNG file
\r
88 if( png_sig_cmp(buffer, 0, 8) )
\r
90 os::Printer::log("LOAD PNG: not really a png\n", file->getFileName(), ELL_ERROR);
\r
94 // Allocate the png read struct
\r
95 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
\r
96 NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warn);
\r
99 os::Printer::log("LOAD PNG: Internal PNG create read struct failure\n", file->getFileName(), ELL_ERROR);
\r
103 // Allocate the png info struct
\r
104 png_infop info_ptr = png_create_info_struct(png_ptr);
\r
107 os::Printer::log("LOAD PNG: Internal PNG create info struct failure\n", file->getFileName(), ELL_ERROR);
\r
108 png_destroy_read_struct(&png_ptr, NULL, NULL);
\r
112 // for proper error handling
\r
113 if (setjmp(png_jmpbuf(png_ptr)))
\r
115 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
\r
116 delete [] RowPointers;
\r
120 // changed by zola so we don't need to have public FILE pointers
\r
121 png_set_read_fn(png_ptr, file, user_read_data_fcn);
\r
123 png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature
\r
125 png_read_info(png_ptr, info_ptr); // Read the info section of the png file
\r
132 // Use temporary variables to avoid passing cast pointers
\r
135 png_get_IHDR(png_ptr, info_ptr,
\r
137 &BitDepth, &ColorType, NULL, NULL, NULL);
\r
142 if (!checkImageDimensions(Width, Height))
\r
143 png_cpexcept_error(png_ptr, "Unreasonable size");
\r
145 // Convert palette color to true color
\r
146 if (ColorType==PNG_COLOR_TYPE_PALETTE)
\r
147 png_set_palette_to_rgb(png_ptr);
\r
149 // Convert low bit colors to 8 bit colors
\r
152 if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
\r
153 png_set_expand_gray_1_2_4_to_8(png_ptr);
\r
155 png_set_packing(png_ptr);
\r
158 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
\r
159 png_set_tRNS_to_alpha(png_ptr);
\r
161 // Convert high bit colors to 8 bit colors
\r
162 if (BitDepth == 16)
\r
163 png_set_strip_16(png_ptr);
\r
165 // Convert gray color to true color
\r
166 if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
\r
167 png_set_gray_to_rgb(png_ptr);
\r
170 const double screen_gamma = 2.2;
\r
172 if (png_get_sRGB(png_ptr, info_ptr, &intent))
\r
173 png_set_gamma(png_ptr, screen_gamma, 0.45455);
\r
176 double image_gamma;
\r
177 if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
\r
178 png_set_gamma(png_ptr, screen_gamma, image_gamma);
\r
180 png_set_gamma(png_ptr, screen_gamma, 0.45455);
\r
183 // Update the changes in between, as we need to get the new color type
\r
184 // for proper processing of the RGBA type
\r
185 png_read_update_info(png_ptr, info_ptr);
\r
187 // Use temporary variables to avoid passing cast pointers
\r
190 png_get_IHDR(png_ptr, info_ptr,
\r
192 &BitDepth, &ColorType, NULL, NULL, NULL);
\r
197 // Convert RGBA to BGRA
\r
198 if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
\r
200 #ifdef __BIG_ENDIAN__
\r
201 png_set_swap_alpha(png_ptr);
\r
203 png_set_bgr(png_ptr);
\r
207 // Create the image structure to be filled by png data
\r
208 video::IImage* image = 0;
\r
209 if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
\r
210 image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(Width, Height));
\r
212 image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(Width, Height));
\r
215 os::Printer::log("LOAD PNG: Internal PNG create image struct failure\n", file->getFileName(), ELL_ERROR);
\r
216 png_destroy_read_struct(&png_ptr, NULL, NULL);
\r
220 // Create array of pointers to rows in image data
\r
221 RowPointers = new png_bytep[Height];
\r
224 os::Printer::log("LOAD PNG: Internal PNG create row pointers failure\n", file->getFileName(), ELL_ERROR);
\r
225 png_destroy_read_struct(&png_ptr, NULL, NULL);
\r
230 // Fill array of pointers to rows in image data
\r
231 unsigned char* data = (unsigned char*)image->getData();
\r
232 for (u32 i=0; i<Height; ++i)
\r
234 RowPointers[i]=data;
\r
235 data += image->getPitch();
\r
238 // for proper error handling
\r
239 if (setjmp(png_jmpbuf(png_ptr)))
\r
241 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
\r
242 delete [] RowPointers;
\r
247 // Read data using the library function that handles all transformations including interlacing
\r
248 png_read_image(png_ptr, RowPointers);
\r
250 png_read_end(png_ptr, NULL);
\r
251 delete [] RowPointers;
\r
252 png_destroy_read_struct(&png_ptr,&info_ptr, 0); // Clean up memory
\r
258 IImageLoader* createImageLoaderPNG()
\r
260 return new CImageLoaderPng();
\r
264 }// end namespace irr
\r
265 }//end namespace video
\r