]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CImageWriterPNG.cpp
Unify & improve log messages
[irrlicht.git] / source / Irrlicht / CImageWriterPNG.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 "CImageWriterPNG.h"\r
6 \r
7 #include "CImageLoaderPNG.h"\r
8 #include "CColorConverter.h"\r
9 #include "IWriteFile.h"\r
10 #include "irrString.h"\r
11 #include "os.h" // for logging\r
12 \r
13 #include <png.h> // use system lib png\r
14 \r
15 namespace irr\r
16 {\r
17 namespace video\r
18 {\r
19 \r
20 IImageWriter* createImageWriterPNG()\r
21 {\r
22         return new CImageWriterPNG;\r
23 }\r
24 \r
25 // PNG function for error handling\r
26 static void png_cpexcept_error(png_structp png_ptr, png_const_charp msg)\r
27 {\r
28         os::Printer::log("PNG fatal error", msg, ELL_ERROR);\r
29         longjmp(png_jmpbuf(png_ptr), 1);\r
30 }\r
31 \r
32 // PNG function for warning handling\r
33 static void png_cpexcept_warning(png_structp png_ptr, png_const_charp msg)\r
34 {\r
35         os::Printer::log("PNG warning", msg, ELL_WARNING);\r
36 }\r
37 \r
38 // PNG function for file writing\r
39 void PNGAPI user_write_data_fcn(png_structp png_ptr, png_bytep data, png_size_t length)\r
40 {\r
41         png_size_t check;\r
42 \r
43         io::IWriteFile* file=(io::IWriteFile*)png_get_io_ptr(png_ptr);\r
44         check=(png_size_t) file->write((const void*)data, length);\r
45 \r
46         if (check != length)\r
47                 png_error(png_ptr, "Write Error");\r
48 }\r
49 \r
50 CImageWriterPNG::CImageWriterPNG()\r
51 {\r
52 #ifdef _DEBUG\r
53         setDebugName("CImageWriterPNG");\r
54 #endif\r
55 }\r
56 \r
57 bool CImageWriterPNG::isAWriteableFileExtension(const io::path& filename) const\r
58 {\r
59         return core::hasFileExtension ( filename, "png" );\r
60 }\r
61 \r
62 bool CImageWriterPNG::writeImage(io::IWriteFile* file, IImage* image,u32 param) const\r
63 {\r
64         if (!file || !image)\r
65                 return false;\r
66 \r
67         // Allocate the png write struct\r
68         png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,\r
69                 NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warning);\r
70         if (!png_ptr)\r
71         {\r
72                 os::Printer::log("PNGWriter: Internal PNG create write struct failure", file->getFileName(), ELL_ERROR);\r
73                 return false;\r
74         }\r
75 \r
76         // Allocate the png info struct\r
77         png_infop info_ptr = png_create_info_struct(png_ptr);\r
78         if (!info_ptr)\r
79         {\r
80                 os::Printer::log("PNGWriter: Internal PNG create info struct failure", file->getFileName(), ELL_ERROR);\r
81                 png_destroy_write_struct(&png_ptr, NULL);\r
82                 return false;\r
83         }\r
84 \r
85         // for proper error handling\r
86         if (setjmp(png_jmpbuf(png_ptr)))\r
87         {\r
88                 png_destroy_write_struct(&png_ptr, &info_ptr);\r
89                 return false;\r
90         }\r
91 \r
92         png_set_write_fn(png_ptr, file, user_write_data_fcn, NULL);\r
93 \r
94         // Set info\r
95         switch(image->getColorFormat())\r
96         {\r
97                 case ECF_A8R8G8B8:\r
98                 case ECF_A1R5G5B5:\r
99                         png_set_IHDR(png_ptr, info_ptr,\r
100                                 image->getDimension().Width, image->getDimension().Height,\r
101                                 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,\r
102                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);\r
103                 break;\r
104                 default:\r
105                         png_set_IHDR(png_ptr, info_ptr,\r
106                                 image->getDimension().Width, image->getDimension().Height,\r
107                                 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,\r
108                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);\r
109         }\r
110 \r
111         s32 lineWidth = image->getDimension().Width;\r
112         switch(image->getColorFormat())\r
113         {\r
114         case ECF_R8G8B8:\r
115         case ECF_R5G6B5:\r
116                 lineWidth*=3;\r
117                 break;\r
118         case ECF_A8R8G8B8:\r
119         case ECF_A1R5G5B5:\r
120                 lineWidth*=4;\r
121                 break;\r
122         // TODO: Error handling in case of unsupported color format\r
123         default:\r
124                 break;\r
125         }\r
126         u8* tmpImage = new u8[image->getDimension().Height*lineWidth];\r
127         if (!tmpImage)\r
128         {\r
129                 os::Printer::log("PNGWriter: Internal PNG create image failure", file->getFileName(), ELL_ERROR);\r
130                 png_destroy_write_struct(&png_ptr, &info_ptr);\r
131                 return false;\r
132         }\r
133 \r
134         u8* data = (u8*)image->getData();\r
135         switch(image->getColorFormat())\r
136         {\r
137         case ECF_R8G8B8:\r
138                 CColorConverter::convert_R8G8B8toR8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);\r
139                 break;\r
140         case ECF_A8R8G8B8:\r
141                 CColorConverter::convert_A8R8G8B8toA8R8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);\r
142                 break;\r
143         case ECF_R5G6B5:\r
144                 CColorConverter::convert_R5G6B5toR8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);\r
145                 break;\r
146         case ECF_A1R5G5B5:\r
147                 CColorConverter::convert_A1R5G5B5toA8R8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);\r
148                 break;\r
149                 // TODO: Error handling in case of unsupported color format\r
150         default:\r
151                 os::Printer::log("CImageWriterPNG does not support image format", ColorFormatNames[image->getColorFormat()], ELL_WARNING);\r
152                 png_destroy_write_struct(&png_ptr, &info_ptr);\r
153                 delete [] tmpImage;\r
154                 return false;\r
155         }\r
156 \r
157         // Create array of pointers to rows in image data\r
158 \r
159         //Used to point to image rows\r
160         u8** RowPointers = new png_bytep[image->getDimension().Height];\r
161         if (!RowPointers)\r
162         {\r
163                 os::Printer::log("PNGWriter: Internal PNG create row pointers failure", file->getFileName(), ELL_ERROR);\r
164                 png_destroy_write_struct(&png_ptr, &info_ptr);\r
165                 delete [] tmpImage;\r
166                 return false;\r
167         }\r
168 \r
169         data=tmpImage;\r
170         // Fill array of pointers to rows in image data\r
171         for (u32 i=0; i<image->getDimension().Height; ++i)\r
172         {\r
173                 RowPointers[i]=data;\r
174                 data += lineWidth;\r
175         }\r
176         // for proper error handling\r
177         if (setjmp(png_jmpbuf(png_ptr)))\r
178         {\r
179                 png_destroy_write_struct(&png_ptr, &info_ptr);\r
180                 delete [] RowPointers;\r
181                 delete [] tmpImage;\r
182                 return false;\r
183         }\r
184 \r
185         png_set_rows(png_ptr, info_ptr, RowPointers);\r
186 \r
187         if (image->getColorFormat()==ECF_A8R8G8B8 || image->getColorFormat()==ECF_A1R5G5B5)\r
188                 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL);\r
189         else\r
190         {\r
191                 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);\r
192         }\r
193 \r
194         delete [] RowPointers;\r
195         delete [] tmpImage;\r
196         png_destroy_write_struct(&png_ptr, &info_ptr);\r
197         return true;\r
198 }\r
199 \r
200 } // namespace video\r
201 } // namespace irr\r