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