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