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