1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the libgltf project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10 #include <PNGHelper.h>
11 #include <iostream>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <png.h>
15
16 namespace libgltf { namespace pnghelper
17 {
18
ReadPNGFromFile(const std::string & sFileName,char ** pBuffer,int & nWidth,int & nHeight)19 bool ReadPNGFromFile(const std::string& sFileName, char** pBuffer, int& nWidth, int& nHeight)
20 {
21 unsigned char aHeader[8]; // 8 is the maximum size that can be checked
22
23 /* open file and test for it being a png */
24 FILE* pFile = fopen(sFileName.c_str(), "rb");
25 if( !pFile )
26 {
27 std::cerr << "File " << sFileName.c_str() << " could not be opened for reading" << std::endl;
28 return false;
29 }
30
31 fread(aHeader, 1, 8, pFile);
32 if (png_sig_cmp(aHeader, 0, 8))
33 {
34 std::cerr << "File " << sFileName.c_str() << " is not recognized as a PNG file" << std::endl;
35 return false;
36 }
37
38
39 /* initialization */
40 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
41
42 if (!png_ptr)
43 {
44 std::cerr << "png_create_read_struct failed" << std::endl;
45 return false;
46 }
47
48 png_infop info_ptr = png_create_info_struct(png_ptr);
49 if (!info_ptr)
50 {
51 std::cerr << "png_create_info_struct failed" << std::endl;
52 return false;
53 }
54
55 if (setjmp(png_jmpbuf(png_ptr)))
56 {
57 std::cerr << "Error during init_io" << std::endl;
58 return false;
59 }
60
61 png_init_io(png_ptr, pFile);
62 png_set_sig_bytes(png_ptr, 8);
63
64 png_read_info(png_ptr, info_ptr);
65
66 nWidth = png_get_image_width(png_ptr, info_ptr);
67 nHeight = png_get_image_height(png_ptr, info_ptr);
68
69 png_read_update_info(png_ptr, info_ptr);
70
71 /* read file */
72 if (setjmp(png_jmpbuf(png_ptr)))
73 {
74 std::cerr << "Error during read_image" << std::endl;
75 return false;
76 }
77
78 png_bytep* pRowPointers = (png_bytep*) malloc(sizeof(png_bytep) * nHeight);
79 for (int i = 0; i < nHeight; ++i)
80 {
81 pRowPointers[i] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
82 }
83
84 png_read_image(png_ptr, pRowPointers);
85
86 int nColorType = png_get_color_type(png_ptr, info_ptr);
87
88 if( nColorType != PNG_COLOR_TYPE_RGB && nColorType != PNG_COLOR_TYPE_RGBA )
89 {
90 std::cerr << "Input file must be PNG_COLOR_TYPE_RGB or PNG_COLOR_TYPE_RGBA" << std::endl;
91 return false;
92 }
93
94 (*pBuffer) = new char[4*nWidth*nHeight];
95 unsigned nIndex = 0;
96 for (int i = 0; i < nHeight; ++i)
97 {
98 png_byte* pRow = pRowPointers[i];
99 for ( int j = 0; j < nWidth; ++j)
100 {
101 png_byte* pPtr;
102 if( nColorType == PNG_COLOR_TYPE_RGB )
103 {
104 pPtr = &(pRow[j*3]);
105 }
106 else
107 {
108 pPtr = &(pRow[j*4]);
109 }
110 (*pBuffer)[nIndex++] = pPtr[0];
111 (*pBuffer)[nIndex++] = pPtr[1];
112 (*pBuffer)[nIndex++] = pPtr[2];
113 if( nColorType == PNG_COLOR_TYPE_RGB )
114 {
115 (*pBuffer)[nIndex++] = 127;
116 }
117 else
118 {
119 (*pBuffer)[nIndex++] = pPtr[3];
120 }
121 }
122 }
123
124 fclose(pFile);
125 return true;
126 }
127
WritePNGToFile(const std::string & sFileName,const char * pBuffer,const int nWidth,const int nHeight)128 bool WritePNGToFile(const std::string& sFileName, const char* pBuffer, const int nWidth, const int nHeight)
129 {
130 /* create file */
131 FILE *pFile = fopen(sFileName.c_str(), "wb");
132 if (!pFile)
133 {
134 std::cerr << "File " << sFileName.c_str() << " could not be opened for writing" << std::endl;
135 return false;
136 }
137
138 /* initialize stuff */
139 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
140
141 if (!png_ptr)
142 {
143 std::cerr << "png_create_write_struct failed" << std::endl;
144 return false;
145 }
146
147 png_infop info_ptr = png_create_info_struct(png_ptr);
148 if (!info_ptr)
149 {
150 std::cerr << "png_create_info_struct failed" << std::endl;
151 return false;
152 }
153
154 if (setjmp(png_jmpbuf(png_ptr)))
155 {
156 std::cerr << "Error during init_io" << std::endl;
157 return false;
158 }
159
160 png_init_io(png_ptr, pFile);
161
162 png_set_IHDR(png_ptr, info_ptr, nWidth, nHeight,
163 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
164 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
165
166 png_bytep* pRowPointers = (png_bytep*)malloc( sizeof(png_bytep) * nHeight);
167 unsigned int nIndex = 0;
168 for (int i = 0; i < nHeight; ++i)
169 {
170 png_byte* pRow = (png_byte*)malloc(sizeof(png_byte) * nWidth * 4);
171 pRowPointers[i] = pRow;
172 for (int j = 0; j < nWidth; ++j)
173 {
174 *pRow++ = pBuffer[nIndex++];
175 *pRow++ = pBuffer[nIndex++];
176 *pRow++ = pBuffer[nIndex++];
177 ++nIndex;
178 }
179 }
180
181 /* write header */
182 if (setjmp(png_jmpbuf(png_ptr)))
183 {
184 std::cerr << "Error during writing header" << std::endl;
185 return false;
186 }
187
188 png_write_info(png_ptr, info_ptr);
189
190 /* write bytes */
191 if (setjmp(png_jmpbuf(png_ptr)))
192 {
193 std::cerr << "Error during writing bytes" << std::endl;
194 return false;
195 }
196
197 png_write_image(png_ptr, pRowPointers);
198
199 /* end write */
200 if (setjmp(png_jmpbuf(png_ptr)))
201 {
202 std::cerr << "Error during end of write" << std::endl;
203 return false;
204 }
205
206 png_write_end(png_ptr, NULL);
207
208 /* cleanup heap allocation */
209 for (int i = 0; i < nHeight; ++i)
210 {
211 free(pRowPointers[i]);
212 }
213 free(pRowPointers);
214
215 fclose(pFile);
216 return true;
217 }
218
219 } // pnghelper
220 } // libgltf
221