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 #ifdef _IRR_COMPILE_WITH_PNG_LOADER_
\r
9 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
10 #include <png.h> // use system lib png
\r
11 #endif // _IRR_COMPILE_WITH_LIBPNG_
\r
14 #include "CReadFile.h"
\r
22 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
23 // PNG function for error handling
\r
24 static void png_cpexcept_error(png_structp png_ptr, png_const_charp msg)
\r
26 os::Printer::log("PNG fatal error", msg, ELL_ERROR);
\r
27 longjmp(png_jmpbuf(png_ptr), 1);
\r
30 // PNG function for warning handling
\r
31 static void png_cpexcept_warn(png_structp png_ptr, png_const_charp msg)
\r
33 os::Printer::log("PNG warning", msg, ELL_WARNING);
\r
36 // PNG function for file reading
\r
37 void PNGAPI user_read_data_fcn(png_structp png_ptr, png_bytep data, png_size_t length)
\r
41 // changed by zola {
\r
42 io::IReadFile* file=(io::IReadFile*)png_get_io_ptr(png_ptr);
\r
43 check=(png_size_t) file->read((void*)data,(u32)length);
\r
46 if (check != length)
\r
47 png_error(png_ptr, "Read Error");
\r
49 #endif // _IRR_COMPILE_WITH_LIBPNG_
\r
52 //! returns true if the file maybe is able to be loaded by this class
\r
53 //! based on the file extension (e.g. ".tga")
\r
54 bool CImageLoaderPng::isALoadableFileExtension(const io::path& filename) const
\r
56 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
57 return core::hasFileExtension ( filename, "png" );
\r
60 #endif // _IRR_COMPILE_WITH_LIBPNG_
\r
64 //! returns true if the file maybe is able to be loaded by this class
\r
65 bool CImageLoaderPng::isALoadableFileFormat(io::IReadFile* file) const
\r
67 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
72 // Read the first few bytes of the PNG file
\r
73 if (file->read(buffer, 8) != 8)
\r
76 // Check if it really is a PNG file
\r
77 return !png_sig_cmp(buffer, 0, 8);
\r
80 #endif // _IRR_COMPILE_WITH_LIBPNG_
\r
84 // load in the image data
\r
85 IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const
\r
87 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
91 //Used to point to image rows
\r
92 u8** RowPointers = 0;
\r
95 // Read the first few bytes of the PNG file
\r
96 if( file->read(buffer, 8) != 8 )
\r
98 os::Printer::log("LOAD PNG: can't read file\n", file->getFileName(), ELL_ERROR);
\r
102 // Check if it really is a PNG file
\r
103 if( png_sig_cmp(buffer, 0, 8) )
\r
105 os::Printer::log("LOAD PNG: not really a png\n", file->getFileName(), ELL_ERROR);
\r
109 // Allocate the png read struct
\r
110 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
\r
111 NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warn);
\r
114 os::Printer::log("LOAD PNG: Internal PNG create read struct failure\n", file->getFileName(), ELL_ERROR);
\r
118 // Allocate the png info struct
\r
119 png_infop info_ptr = png_create_info_struct(png_ptr);
\r
122 os::Printer::log("LOAD PNG: Internal PNG create info struct failure\n", file->getFileName(), ELL_ERROR);
\r
123 png_destroy_read_struct(&png_ptr, NULL, NULL);
\r
127 // for proper error handling
\r
128 if (setjmp(png_jmpbuf(png_ptr)))
\r
130 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
\r
131 delete [] RowPointers;
\r
135 // changed by zola so we don't need to have public FILE pointers
\r
136 png_set_read_fn(png_ptr, file, user_read_data_fcn);
\r
138 png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature
\r
140 png_read_info(png_ptr, info_ptr); // Read the info section of the png file
\r
147 // Use temporary variables to avoid passing cast pointers
\r
150 png_get_IHDR(png_ptr, info_ptr,
\r
152 &BitDepth, &ColorType, NULL, NULL, NULL);
\r
157 // Convert palette color to true color
\r
158 if (ColorType==PNG_COLOR_TYPE_PALETTE)
\r
159 png_set_palette_to_rgb(png_ptr);
\r
161 // Convert low bit colors to 8 bit colors
\r
164 if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
\r
165 png_set_expand_gray_1_2_4_to_8(png_ptr);
\r
167 png_set_packing(png_ptr);
\r
170 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
\r
171 png_set_tRNS_to_alpha(png_ptr);
\r
173 // Convert high bit colors to 8 bit colors
\r
174 if (BitDepth == 16)
\r
175 png_set_strip_16(png_ptr);
\r
177 // Convert gray color to true color
\r
178 if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
\r
179 png_set_gray_to_rgb(png_ptr);
\r
182 const double screen_gamma = 2.2;
\r
184 if (png_get_sRGB(png_ptr, info_ptr, &intent))
\r
185 png_set_gamma(png_ptr, screen_gamma, 0.45455);
\r
188 double image_gamma;
\r
189 if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
\r
190 png_set_gamma(png_ptr, screen_gamma, image_gamma);
\r
192 png_set_gamma(png_ptr, screen_gamma, 0.45455);
\r
195 // Update the changes in between, as we need to get the new color type
\r
196 // for proper processing of the RGBA type
\r
197 png_read_update_info(png_ptr, info_ptr);
\r
199 // Use temporary variables to avoid passing cast pointers
\r
202 png_get_IHDR(png_ptr, info_ptr,
\r
204 &BitDepth, &ColorType, NULL, NULL, NULL);
\r
209 // Convert RGBA to BGRA
\r
210 if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
\r
212 #ifdef __BIG_ENDIAN__
\r
213 png_set_swap_alpha(png_ptr);
\r
215 png_set_bgr(png_ptr);
\r
219 // Create the image structure to be filled by png data
\r
220 video::IImage* image = 0;
\r
221 if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
\r
222 image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(Width, Height));
\r
224 image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(Width, Height));
\r
227 os::Printer::log("LOAD PNG: Internal PNG create image struct failure\n", file->getFileName(), ELL_ERROR);
\r
228 png_destroy_read_struct(&png_ptr, NULL, NULL);
\r
232 // Create array of pointers to rows in image data
\r
233 RowPointers = new png_bytep[Height];
\r
236 os::Printer::log("LOAD PNG: Internal PNG create row pointers failure\n", file->getFileName(), ELL_ERROR);
\r
237 png_destroy_read_struct(&png_ptr, NULL, NULL);
\r
242 // Fill array of pointers to rows in image data
\r
243 unsigned char* data = (unsigned char*)image->getData();
\r
244 for (u32 i=0; i<Height; ++i)
\r
246 RowPointers[i]=data;
\r
247 data += image->getPitch();
\r
250 // for proper error handling
\r
251 if (setjmp(png_jmpbuf(png_ptr)))
\r
253 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
\r
254 delete [] RowPointers;
\r
259 // Read data using the library function that handles all transformations including interlacing
\r
260 png_read_image(png_ptr, RowPointers);
\r
262 png_read_end(png_ptr, NULL);
\r
263 delete [] RowPointers;
\r
264 png_destroy_read_struct(&png_ptr,&info_ptr, 0); // Clean up memory
\r
269 #endif // _IRR_COMPILE_WITH_LIBPNG_
\r
273 IImageLoader* createImageLoaderPNG()
\r
275 return new CImageLoaderPng();
\r
279 }// end namespace irr
\r
280 }//end namespace video
\r