|
1 //------------------------------------- |
|
2 // PNGFILE.C -- Image File Functions |
|
3 //------------------------------------- |
|
4 |
|
5 // Copyright 2000, Willem van Schaik. For conditions of distribution and |
|
6 // use, see the copyright/license/disclaimer notice in png.h |
|
7 |
|
8 #include <windows.h> |
|
9 #include <commdlg.h> |
|
10 #include <stdio.h> |
|
11 #include <stdlib.h> |
|
12 |
|
13 #include "png.h" |
|
14 #include "pngfile.h" |
|
15 #include "cexcept.h" |
|
16 |
|
17 define_exception_type(const char *); |
|
18 extern struct exception_context the_exception_context[1]; |
|
19 struct exception_context the_exception_context[1]; |
|
20 png_const_charp msg; |
|
21 |
|
22 static OPENFILENAME ofn; |
|
23 |
|
24 static png_structp png_ptr = NULL; |
|
25 static png_infop info_ptr = NULL; |
|
26 |
|
27 |
|
28 // cexcept interface |
|
29 |
|
30 static void |
|
31 png_cexcept_error(png_structp png_ptr, png_const_charp msg) |
|
32 { |
|
33 if(png_ptr) |
|
34 ; |
|
35 #ifndef PNG_NO_CONSOLE_IO |
|
36 fprintf(stderr, "libpng error: %s\n", msg); |
|
37 #endif |
|
38 { |
|
39 Throw msg; |
|
40 } |
|
41 } |
|
42 |
|
43 // Windows open-file functions |
|
44 |
|
45 void PngFileInitialize (HWND hwnd) |
|
46 { |
|
47 static TCHAR szFilter[] = TEXT ("PNG Files (*.PNG)\0*.png\0") |
|
48 TEXT ("All Files (*.*)\0*.*\0\0"); |
|
49 |
|
50 ofn.lStructSize = sizeof (OPENFILENAME); |
|
51 ofn.hwndOwner = hwnd; |
|
52 ofn.hInstance = NULL; |
|
53 ofn.lpstrFilter = szFilter; |
|
54 ofn.lpstrCustomFilter = NULL; |
|
55 ofn.nMaxCustFilter = 0; |
|
56 ofn.nFilterIndex = 0; |
|
57 ofn.lpstrFile = NULL; // Set in Open and Close functions |
|
58 ofn.nMaxFile = MAX_PATH; |
|
59 ofn.lpstrFileTitle = NULL; // Set in Open and Close functions |
|
60 ofn.nMaxFileTitle = MAX_PATH; |
|
61 ofn.lpstrInitialDir = NULL; |
|
62 ofn.lpstrTitle = NULL; |
|
63 ofn.Flags = 0; // Set in Open and Close functions |
|
64 ofn.nFileOffset = 0; |
|
65 ofn.nFileExtension = 0; |
|
66 ofn.lpstrDefExt = TEXT ("png"); |
|
67 ofn.lCustData = 0; |
|
68 ofn.lpfnHook = NULL; |
|
69 ofn.lpTemplateName = NULL; |
|
70 } |
|
71 |
|
72 BOOL PngFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) |
|
73 { |
|
74 ofn.hwndOwner = hwnd; |
|
75 ofn.lpstrFile = pstrFileName; |
|
76 ofn.lpstrFileTitle = pstrTitleName; |
|
77 ofn.Flags = OFN_HIDEREADONLY; |
|
78 |
|
79 return GetOpenFileName (&ofn); |
|
80 } |
|
81 |
|
82 BOOL PngFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) |
|
83 { |
|
84 ofn.hwndOwner = hwnd; |
|
85 ofn.lpstrFile = pstrFileName; |
|
86 ofn.lpstrFileTitle = pstrTitleName; |
|
87 ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; |
|
88 |
|
89 return GetSaveFileName (&ofn); |
|
90 } |
|
91 |
|
92 // PNG image handler functions |
|
93 |
|
94 BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData, |
|
95 int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor) |
|
96 { |
|
97 static FILE *pfFile; |
|
98 png_byte pbSig[8]; |
|
99 int iBitDepth; |
|
100 int iColorType; |
|
101 double dGamma; |
|
102 png_color_16 *pBackground; |
|
103 png_uint_32 ulChannels; |
|
104 png_uint_32 ulRowBytes; |
|
105 png_byte *pbImageData = *ppbImageData; |
|
106 static png_byte **ppbRowPointers = NULL; |
|
107 int i; |
|
108 |
|
109 // open the PNG input file |
|
110 |
|
111 if (!pstrFileName) |
|
112 { |
|
113 *ppbImageData = pbImageData = NULL; |
|
114 return FALSE; |
|
115 } |
|
116 |
|
117 if (!(pfFile = fopen(pstrFileName, "rb"))) |
|
118 { |
|
119 *ppbImageData = pbImageData = NULL; |
|
120 return FALSE; |
|
121 } |
|
122 |
|
123 // first check the eight byte PNG signature |
|
124 |
|
125 fread(pbSig, 1, 8, pfFile); |
|
126 if (!png_check_sig(pbSig, 8)) |
|
127 { |
|
128 *ppbImageData = pbImageData = NULL; |
|
129 return FALSE; |
|
130 } |
|
131 |
|
132 // create the two png(-info) structures |
|
133 |
|
134 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, |
|
135 (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); |
|
136 if (!png_ptr) |
|
137 { |
|
138 *ppbImageData = pbImageData = NULL; |
|
139 return FALSE; |
|
140 } |
|
141 |
|
142 info_ptr = png_create_info_struct(png_ptr); |
|
143 if (!info_ptr) |
|
144 { |
|
145 png_destroy_read_struct(&png_ptr, NULL, NULL); |
|
146 *ppbImageData = pbImageData = NULL; |
|
147 return FALSE; |
|
148 } |
|
149 |
|
150 Try |
|
151 { |
|
152 |
|
153 // initialize the png structure |
|
154 |
|
155 #if !defined(PNG_NO_STDIO) |
|
156 png_init_io(png_ptr, pfFile); |
|
157 #else |
|
158 png_set_read_fn(png_ptr, (png_voidp)pfFile, png_read_data); |
|
159 #endif |
|
160 |
|
161 png_set_sig_bytes(png_ptr, 8); |
|
162 |
|
163 // read all PNG info up to image data |
|
164 |
|
165 png_read_info(png_ptr, info_ptr); |
|
166 |
|
167 // get width, height, bit-depth and color-type |
|
168 |
|
169 png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth, |
|
170 &iColorType, NULL, NULL, NULL); |
|
171 |
|
172 // expand images of all color-type and bit-depth to 3x8 bit RGB images |
|
173 // let the library process things like alpha, transparency, background |
|
174 |
|
175 if (iBitDepth == 16) |
|
176 png_set_strip_16(png_ptr); |
|
177 if (iColorType == PNG_COLOR_TYPE_PALETTE) |
|
178 png_set_expand(png_ptr); |
|
179 if (iBitDepth < 8) |
|
180 png_set_expand(png_ptr); |
|
181 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) |
|
182 png_set_expand(png_ptr); |
|
183 if (iColorType == PNG_COLOR_TYPE_GRAY || |
|
184 iColorType == PNG_COLOR_TYPE_GRAY_ALPHA) |
|
185 png_set_gray_to_rgb(png_ptr); |
|
186 |
|
187 // set the background color to draw transparent and alpha images over. |
|
188 if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) |
|
189 { |
|
190 png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); |
|
191 pBkgColor->red = (byte) pBackground->red; |
|
192 pBkgColor->green = (byte) pBackground->green; |
|
193 pBkgColor->blue = (byte) pBackground->blue; |
|
194 } |
|
195 else |
|
196 { |
|
197 pBkgColor = NULL; |
|
198 } |
|
199 |
|
200 // if required set gamma conversion |
|
201 if (png_get_gAMA(png_ptr, info_ptr, &dGamma)) |
|
202 png_set_gamma(png_ptr, (double) 2.2, dGamma); |
|
203 |
|
204 // after the transformations have been registered update info_ptr data |
|
205 |
|
206 png_read_update_info(png_ptr, info_ptr); |
|
207 |
|
208 // get again width, height and the new bit-depth and color-type |
|
209 |
|
210 png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth, |
|
211 &iColorType, NULL, NULL, NULL); |
|
212 |
|
213 |
|
214 // row_bytes is the width x number of channels |
|
215 |
|
216 ulRowBytes = png_get_rowbytes(png_ptr, info_ptr); |
|
217 ulChannels = png_get_channels(png_ptr, info_ptr); |
|
218 |
|
219 *piChannels = ulChannels; |
|
220 |
|
221 // now we can allocate memory to store the image |
|
222 |
|
223 if (pbImageData) |
|
224 { |
|
225 free (pbImageData); |
|
226 pbImageData = NULL; |
|
227 } |
|
228 if ((pbImageData = (png_byte *) malloc(ulRowBytes * (*piHeight) |
|
229 * sizeof(png_byte))) == NULL) |
|
230 { |
|
231 png_error(png_ptr, "Visual PNG: out of memory"); |
|
232 } |
|
233 *ppbImageData = pbImageData; |
|
234 |
|
235 // and allocate memory for an array of row-pointers |
|
236 |
|
237 if ((ppbRowPointers = (png_bytepp) malloc((*piHeight) |
|
238 * sizeof(png_bytep))) == NULL) |
|
239 { |
|
240 png_error(png_ptr, "Visual PNG: out of memory"); |
|
241 } |
|
242 |
|
243 // set the individual row-pointers to point at the correct offsets |
|
244 |
|
245 for (i = 0; i < (*piHeight); i++) |
|
246 ppbRowPointers[i] = pbImageData + i * ulRowBytes; |
|
247 |
|
248 // now we can go ahead and just read the whole image |
|
249 |
|
250 png_read_image(png_ptr, ppbRowPointers); |
|
251 |
|
252 // read the additional chunks in the PNG file (not really needed) |
|
253 |
|
254 png_read_end(png_ptr, NULL); |
|
255 |
|
256 // and we're done |
|
257 |
|
258 free (ppbRowPointers); |
|
259 ppbRowPointers = NULL; |
|
260 |
|
261 // yepp, done |
|
262 } |
|
263 |
|
264 Catch (msg) |
|
265 { |
|
266 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
|
267 |
|
268 *ppbImageData = pbImageData = NULL; |
|
269 |
|
270 if(ppbRowPointers) |
|
271 free (ppbRowPointers); |
|
272 |
|
273 fclose(pfFile); |
|
274 |
|
275 return FALSE; |
|
276 } |
|
277 |
|
278 fclose (pfFile); |
|
279 |
|
280 return TRUE; |
|
281 } |
|
282 |
|
283 |
|
284 BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData, |
|
285 int iWidth, int iHeight, png_color bkgColor) |
|
286 { |
|
287 const int ciBitDepth = 8; |
|
288 const int ciChannels = 3; |
|
289 |
|
290 static FILE *pfFile; |
|
291 png_uint_32 ulRowBytes; |
|
292 static png_byte **ppbRowPointers = NULL; |
|
293 int i; |
|
294 |
|
295 // open the PNG output file |
|
296 |
|
297 if (!pstrFileName) |
|
298 return FALSE; |
|
299 |
|
300 if (!(pfFile = fopen(pstrFileName, "wb"))) |
|
301 return FALSE; |
|
302 |
|
303 // prepare the standard PNG structures |
|
304 |
|
305 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, |
|
306 (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); |
|
307 if (!png_ptr) |
|
308 { |
|
309 fclose(pfFile); |
|
310 return FALSE; |
|
311 } |
|
312 |
|
313 info_ptr = png_create_info_struct(png_ptr); |
|
314 if (!info_ptr) { |
|
315 fclose(pfFile); |
|
316 png_destroy_write_struct(&png_ptr, (png_infopp) NULL); |
|
317 return FALSE; |
|
318 } |
|
319 |
|
320 Try |
|
321 { |
|
322 // initialize the png structure |
|
323 |
|
324 #if !defined(PNG_NO_STDIO) |
|
325 png_init_io(png_ptr, pfFile); |
|
326 #else |
|
327 png_set_write_fn(png_ptr, (png_voidp)pfFile, png_write_data, png_flush); |
|
328 #endif |
|
329 |
|
330 // we're going to write a very simple 3x8 bit RGB image |
|
331 |
|
332 png_set_IHDR(png_ptr, info_ptr, iWidth, iHeight, ciBitDepth, |
|
333 PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, |
|
334 PNG_FILTER_TYPE_BASE); |
|
335 |
|
336 // write the file header information |
|
337 |
|
338 png_write_info(png_ptr, info_ptr); |
|
339 |
|
340 // swap the BGR pixels in the DiData structure to RGB |
|
341 |
|
342 png_set_bgr(png_ptr); |
|
343 |
|
344 // row_bytes is the width x number of channels |
|
345 |
|
346 ulRowBytes = iWidth * ciChannels; |
|
347 |
|
348 // we can allocate memory for an array of row-pointers |
|
349 |
|
350 if ((ppbRowPointers = (png_bytepp) malloc(iHeight * sizeof(png_bytep))) == NULL) |
|
351 Throw "Visualpng: Out of memory"; |
|
352 |
|
353 // set the individual row-pointers to point at the correct offsets |
|
354 |
|
355 for (i = 0; i < iHeight; i++) |
|
356 ppbRowPointers[i] = pDiData + i * (((ulRowBytes + 3) >> 2) << 2); |
|
357 |
|
358 // write out the entire image data in one call |
|
359 |
|
360 png_write_image (png_ptr, ppbRowPointers); |
|
361 |
|
362 // write the additional chunks to the PNG file (not really needed) |
|
363 |
|
364 png_write_end(png_ptr, info_ptr); |
|
365 |
|
366 // and we're done |
|
367 |
|
368 free (ppbRowPointers); |
|
369 ppbRowPointers = NULL; |
|
370 |
|
371 // clean up after the write, and free any memory allocated |
|
372 |
|
373 png_destroy_write_struct(&png_ptr, (png_infopp) NULL); |
|
374 |
|
375 // yepp, done |
|
376 } |
|
377 |
|
378 Catch (msg) |
|
379 { |
|
380 png_destroy_write_struct(&png_ptr, (png_infopp) NULL); |
|
381 |
|
382 if(ppbRowPointers) |
|
383 free (ppbRowPointers); |
|
384 |
|
385 fclose(pfFile); |
|
386 |
|
387 return FALSE; |
|
388 } |
|
389 |
|
390 fclose (pfFile); |
|
391 |
|
392 return TRUE; |
|
393 } |
|
394 |
|
395 #ifdef PNG_NO_STDIO |
|
396 |
|
397 static void |
|
398 png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) |
|
399 { |
|
400 png_size_t check; |
|
401 |
|
402 /* fread() returns 0 on error, so it is OK to store this in a png_size_t |
|
403 * instead of an int, which is what fread() actually returns. |
|
404 */ |
|
405 check = (png_size_t)fread(data, (png_size_t)1, length, |
|
406 (FILE *)png_ptr->io_ptr); |
|
407 |
|
408 if (check != length) |
|
409 { |
|
410 png_error(png_ptr, "Read Error"); |
|
411 } |
|
412 } |
|
413 |
|
414 static void |
|
415 png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) |
|
416 { |
|
417 png_uint_32 check; |
|
418 |
|
419 check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr)); |
|
420 if (check != length) |
|
421 { |
|
422 png_error(png_ptr, "Write Error"); |
|
423 } |
|
424 } |
|
425 |
|
426 static void |
|
427 png_flush(png_structp png_ptr) |
|
428 { |
|
429 FILE *io_ptr; |
|
430 io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr)); |
|
431 if (io_ptr != NULL) |
|
432 fflush(io_ptr); |
|
433 } |
|
434 |
|
435 #endif |
|
436 |
|
437 //----------------- |
|
438 // end of source |
|
439 //----------------- |