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 "CImageWriterPNG.h"
\r
7 #ifdef _IRR_COMPILE_WITH_PNG_WRITER_
\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
15 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
16 #include <png.h> // use system lib png
\r
17 #endif // _IRR_COMPILE_WITH_LIBPNG_
\r
24 IImageWriter* createImageWriterPNG()
\r
26 return new CImageWriterPNG;
\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
33 os::Printer::log("PNG fatal error", msg, ELL_ERROR);
\r
34 longjmp(png_jmpbuf(png_ptr), 1);
\r
37 // PNG function for warning handling
\r
38 static void png_cpexcept_warning(png_structp png_ptr, png_const_charp msg)
\r
40 os::Printer::log("PNG warning", msg, ELL_WARNING);
\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
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
51 if (check != length)
\r
52 png_error(png_ptr, "Write Error");
\r
54 #endif // _IRR_COMPILE_WITH_LIBPNG_
\r
56 CImageWriterPNG::CImageWriterPNG()
\r
59 setDebugName("CImageWriterPNG");
\r
63 bool CImageWriterPNG::isAWriteableFileExtension(const io::path& filename) const
\r
65 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
66 return core::hasFileExtension ( filename, "png" );
\r
72 bool CImageWriterPNG::writeImage(io::IWriteFile* file, IImage* image,u32 param) const
\r
74 #ifdef _IRR_COMPILE_WITH_LIBPNG_
\r
75 if (!file || !image)
\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
83 os::Printer::log("PNGWriter: Internal PNG create write struct failure\n", file->getFileName(), ELL_ERROR);
\r
87 // Allocate the png info struct
\r
88 png_infop info_ptr = png_create_info_struct(png_ptr);
\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
96 // for proper error handling
\r
97 if (setjmp(png_jmpbuf(png_ptr)))
\r
99 png_destroy_write_struct(&png_ptr, &info_ptr);
\r
103 png_set_write_fn(png_ptr, file, user_write_data_fcn, NULL);
\r
106 switch(image->getColorFormat())
\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
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
122 s32 lineWidth = image->getDimension().Width;
\r
123 switch(image->getColorFormat())
\r
133 // TODO: Error handling in case of unsupported color format
\r
137 u8* tmpImage = new u8[image->getDimension().Height*lineWidth];
\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
145 u8* data = (u8*)image->getData();
\r
146 switch(image->getColorFormat())
\r
149 CColorConverter::convert_R8G8B8toR8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);
\r
152 CColorConverter::convert_A8R8G8B8toA8R8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);
\r
155 CColorConverter::convert_R5G6B5toR8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);
\r
158 CColorConverter::convert_A1R5G5B5toA8R8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage);
\r
160 // TODO: Error handling in case of unsupported color format
\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
168 // Create array of pointers to rows in image data
\r
170 //Used to point to image rows
\r
171 u8** RowPointers = new png_bytep[image->getDimension().Height];
\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
181 // Fill array of pointers to rows in image data
\r
182 for (u32 i=0; i<image->getDimension().Height; ++i)
\r
184 RowPointers[i]=data;
\r
187 // for proper error handling
\r
188 if (setjmp(png_jmpbuf(png_ptr)))
\r
190 png_destroy_write_struct(&png_ptr, &info_ptr);
\r
191 delete [] RowPointers;
\r
192 delete [] tmpImage;
\r
196 png_set_rows(png_ptr, info_ptr, RowPointers);
\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
202 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
\r
205 delete [] RowPointers;
\r
206 delete [] tmpImage;
\r
207 png_destroy_write_struct(&png_ptr, &info_ptr);
\r
214 } // namespace video
\r