]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CImageLoaderPNG.cpp
Remove bundled libraries
[irrlicht.git] / source / Irrlicht / CImageLoaderPNG.cpp
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
4 \r
5 #include "CImageLoaderPNG.h"\r
6 \r
7 #ifdef _IRR_COMPILE_WITH_PNG_LOADER_\r
8 \r
9 #ifdef _IRR_COMPILE_WITH_LIBPNG_\r
10         #include <png.h> // use system lib png\r
11 #endif // _IRR_COMPILE_WITH_LIBPNG_\r
12 \r
13 #include "CImage.h"\r
14 #include "CReadFile.h"\r
15 #include "os.h"\r
16 \r
17 namespace irr\r
18 {\r
19 namespace video\r
20 {\r
21 \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
25 {\r
26         os::Printer::log("PNG fatal error", msg, ELL_ERROR);\r
27         longjmp(png_jmpbuf(png_ptr), 1);\r
28 }\r
29 \r
30 // PNG function for warning handling\r
31 static void png_cpexcept_warn(png_structp png_ptr, png_const_charp msg)\r
32 {\r
33         os::Printer::log("PNG warning", msg, ELL_WARNING);\r
34 }\r
35 \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
38 {\r
39         png_size_t check;\r
40 \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
44         // }\r
45 \r
46         if (check != length)\r
47                 png_error(png_ptr, "Read Error");\r
48 }\r
49 #endif // _IRR_COMPILE_WITH_LIBPNG_\r
50 \r
51 \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
55 {\r
56 #ifdef _IRR_COMPILE_WITH_LIBPNG_\r
57         return core::hasFileExtension ( filename, "png" );\r
58 #else\r
59         return false;\r
60 #endif // _IRR_COMPILE_WITH_LIBPNG_\r
61 }\r
62 \r
63 \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
66 {\r
67 #ifdef _IRR_COMPILE_WITH_LIBPNG_\r
68         if (!file)\r
69                 return false;\r
70 \r
71         png_byte buffer[8];\r
72         // Read the first few bytes of the PNG file\r
73         if (file->read(buffer, 8) != 8)\r
74                 return false;\r
75 \r
76         // Check if it really is a PNG file\r
77         return !png_sig_cmp(buffer, 0, 8);\r
78 #else\r
79         return false;\r
80 #endif // _IRR_COMPILE_WITH_LIBPNG_\r
81 }\r
82 \r
83 \r
84 // load in the image data\r
85 IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const\r
86 {\r
87 #ifdef _IRR_COMPILE_WITH_LIBPNG_\r
88         if (!file)\r
89                 return 0;\r
90 \r
91         //Used to point to image rows\r
92         u8** RowPointers = 0;\r
93 \r
94         png_byte buffer[8];\r
95         // Read the first few bytes of the PNG file\r
96         if( file->read(buffer, 8) != 8 )\r
97         {\r
98                 os::Printer::log("LOAD PNG: can't read file\n", file->getFileName(), ELL_ERROR);\r
99                 return 0;\r
100         }\r
101 \r
102         // Check if it really is a PNG file\r
103         if( png_sig_cmp(buffer, 0, 8) )\r
104         {\r
105                 os::Printer::log("LOAD PNG: not really a png\n", file->getFileName(), ELL_ERROR);\r
106                 return 0;\r
107         }\r
108 \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
112         if (!png_ptr)\r
113         {\r
114                 os::Printer::log("LOAD PNG: Internal PNG create read struct failure\n", file->getFileName(), ELL_ERROR);\r
115                 return 0;\r
116         }\r
117 \r
118         // Allocate the png info struct\r
119         png_infop info_ptr = png_create_info_struct(png_ptr);\r
120         if (!info_ptr)\r
121         {\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
124                 return 0;\r
125         }\r
126 \r
127         // for proper error handling\r
128         if (setjmp(png_jmpbuf(png_ptr)))\r
129         {\r
130                 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);\r
131                 delete [] RowPointers;\r
132                 return 0;\r
133         }\r
134 \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
137 \r
138         png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature\r
139 \r
140         png_read_info(png_ptr, info_ptr); // Read the info section of the png file\r
141 \r
142         u32 Width;\r
143         u32 Height;\r
144         s32 BitDepth;\r
145         s32 ColorType;\r
146         {\r
147                 // Use temporary variables to avoid passing cast pointers\r
148                 png_uint_32 w,h;\r
149                 // Extract info\r
150                 png_get_IHDR(png_ptr, info_ptr,\r
151                         &w, &h,\r
152                         &BitDepth, &ColorType, NULL, NULL, NULL);\r
153                 Width=w;\r
154                 Height=h;\r
155         }\r
156 \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
160 \r
161         // Convert low bit colors to 8 bit colors\r
162         if (BitDepth < 8)\r
163         {\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
166                 else\r
167                         png_set_packing(png_ptr);\r
168         }\r
169 \r
170         if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))\r
171                 png_set_tRNS_to_alpha(png_ptr);\r
172 \r
173         // Convert high bit colors to 8 bit colors\r
174         if (BitDepth == 16)\r
175                 png_set_strip_16(png_ptr);\r
176 \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
180 \r
181         int intent;\r
182         const double screen_gamma = 2.2;\r
183 \r
184         if (png_get_sRGB(png_ptr, info_ptr, &intent))\r
185                 png_set_gamma(png_ptr, screen_gamma, 0.45455);\r
186         else\r
187         {\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
191                 else\r
192                         png_set_gamma(png_ptr, screen_gamma, 0.45455);\r
193         }\r
194 \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
198         {\r
199                 // Use temporary variables to avoid passing cast pointers\r
200                 png_uint_32 w,h;\r
201                 // Extract info\r
202                 png_get_IHDR(png_ptr, info_ptr,\r
203                         &w, &h,\r
204                         &BitDepth, &ColorType, NULL, NULL, NULL);\r
205                 Width=w;\r
206                 Height=h;\r
207         }\r
208 \r
209         // Convert RGBA to BGRA\r
210         if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)\r
211         {\r
212 #ifdef __BIG_ENDIAN__\r
213                 png_set_swap_alpha(png_ptr);\r
214 #else\r
215                 png_set_bgr(png_ptr);\r
216 #endif\r
217         }\r
218 \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
223         else\r
224                 image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(Width, Height));\r
225         if (!image)\r
226         {\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
229                 return 0;\r
230         }\r
231 \r
232         // Create array of pointers to rows in image data\r
233         RowPointers = new png_bytep[Height];\r
234         if (!RowPointers)\r
235         {\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
238                 delete image;\r
239                 return 0;\r
240         }\r
241 \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
245         {\r
246                 RowPointers[i]=data;\r
247                 data += image->getPitch();\r
248         }\r
249 \r
250         // for proper error handling\r
251         if (setjmp(png_jmpbuf(png_ptr)))\r
252         {\r
253                 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);\r
254                 delete [] RowPointers;\r
255                 delete image;\r
256                 return 0;\r
257         }\r
258 \r
259         // Read data using the library function that handles all transformations including interlacing\r
260         png_read_image(png_ptr, RowPointers);\r
261 \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
265 \r
266         return image;\r
267 #else\r
268         return 0;\r
269 #endif // _IRR_COMPILE_WITH_LIBPNG_\r
270 }\r
271 \r
272 \r
273 IImageLoader* createImageLoaderPNG()\r
274 {\r
275         return new CImageLoaderPng();\r
276 }\r
277 \r
278 \r
279 }// end namespace irr\r
280 }//end namespace video\r
281 \r
282 #endif\r
283 \r