Home | History | Annotate | Download | only in visupng
      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 
     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 ((pbImageData = (png_byte *) malloc(ulRowBytes * (*piHeight)
    240                             * sizeof(png_byte))) == NULL)
    241         {
    242             png_error(png_ptr, "Visual PNG: out of memory");
    243         }
    244         *ppbImageData = pbImageData;
    245 
    246         /* and allocate memory for an array of row-pointers */
    247 
    248         if ((ppbRowPointers = (png_bytepp) malloc((*piHeight)
    249                             * sizeof(png_bytep))) == NULL)
    250         {
    251             png_error(png_ptr, "Visual PNG: out of memory");
    252         }
    253 
    254         /* set the individual row-pointers to point at the correct offsets */
    255 
    256         for (i = 0; i < (*piHeight); i++)
    257             ppbRowPointers[i] = pbImageData + i * ulRowBytes;
    258 
    259         /* now we can go ahead and just read the whole image */
    260 
    261         png_read_image(png_ptr, ppbRowPointers);
    262 
    263         /* read the additional chunks in the PNG file (not really needed) */
    264 
    265         png_read_end(png_ptr, NULL);
    266 
    267         /* and we're done */
    268 
    269         free (ppbRowPointers);
    270         ppbRowPointers = NULL;
    271 
    272         /* yepp, done */
    273     }
    274 
    275     Catch (msg)
    276     {
    277         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    278 
    279         *ppbImageData = pbImageData = NULL;
    280 
    281         if(ppbRowPointers)
    282             free (ppbRowPointers);
    283 
    284         fclose(pfFile);
    285 
    286         return FALSE;
    287     }
    288 
    289     fclose (pfFile);
    290 
    291     return TRUE;
    292 }
    293 
    294 
    295 BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData,
    296                    int iWidth, int iHeight, png_color bkgColor)
    297 {
    298     const int           ciBitDepth = 8;
    299     const int           ciChannels = 3;
    300 
    301     static FILE        *pfFile;
    302     png_uint_32         ulRowBytes;
    303     static png_byte   **ppbRowPointers = NULL;
    304     int                 i;
    305 
    306     /* open the PNG output file */
    307 
    308     if (!pstrFileName)
    309         return FALSE;
    310 
    311     if (!(pfFile = fopen(pstrFileName, "wb")))
    312         return FALSE;
    313 
    314     /* prepare the standard PNG structures */
    315 
    316     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
    317       (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
    318     if (!png_ptr)
    319     {
    320         fclose(pfFile);
    321         return FALSE;
    322     }
    323 
    324     info_ptr = png_create_info_struct(png_ptr);
    325     if (!info_ptr) {
    326         fclose(pfFile);
    327         png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
    328         return FALSE;
    329     }
    330 
    331     Try
    332     {
    333         /* initialize the png structure */
    334 
    335 #ifdef PNG_STDIO_SUPPORTED
    336         png_init_io(png_ptr, pfFile);
    337 #else
    338         png_set_write_fn(png_ptr, (png_voidp)pfFile, png_write_data, png_flush);
    339 #endif
    340 
    341         /* we're going to write a very simple 3x8-bit RGB image */
    342 
    343         png_set_IHDR(png_ptr, info_ptr, iWidth, iHeight, ciBitDepth,
    344             PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
    345             PNG_FILTER_TYPE_BASE);
    346 
    347         /* write the file header information */
    348 
    349         png_write_info(png_ptr, info_ptr);
    350 
    351         /* swap the BGR pixels in the DiData structure to RGB */
    352 
    353         png_set_bgr(png_ptr);
    354 
    355         /* row_bytes is the width x number of channels */
    356 
    357         ulRowBytes = iWidth * ciChannels;
    358 
    359         /* we can allocate memory for an array of row-pointers */
    360 
    361         if ((ppbRowPointers = (png_bytepp) malloc(iHeight * sizeof(png_bytep))) == NULL)
    362             Throw "Visualpng: Out of memory";
    363 
    364         /* set the individual row-pointers to point at the correct offsets */
    365 
    366         for (i = 0; i < iHeight; i++)
    367             ppbRowPointers[i] = pDiData + i * (((ulRowBytes + 3) >> 2) << 2);
    368 
    369         /* write out the entire image data in one call */
    370 
    371         png_write_image (png_ptr, ppbRowPointers);
    372 
    373         /* write the additional chunks to the PNG file (not really needed) */
    374 
    375         png_write_end(png_ptr, info_ptr);
    376 
    377         /* and we're done */
    378 
    379         free (ppbRowPointers);
    380         ppbRowPointers = NULL;
    381 
    382         /* clean up after the write, and free any memory allocated */
    383 
    384         png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
    385 
    386         /* yepp, done */
    387     }
    388 
    389     Catch (msg)
    390     {
    391         png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
    392 
    393         if(ppbRowPointers)
    394             free (ppbRowPointers);
    395 
    396         fclose(pfFile);
    397 
    398         return FALSE;
    399     }
    400 
    401     fclose (pfFile);
    402 
    403     return TRUE;
    404 }
    405 
    406 #ifndef PNG_STDIO_SUPPORTED
    407 
    408 static void
    409 png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
    410 {
    411    png_size_t check;
    412 
    413    /* fread() returns 0 on error, so it is OK to store this in a png_size_t
    414     * instead of an int, which is what fread() actually returns.
    415     */
    416    check = (png_size_t)fread(data, (png_size_t)1, length,
    417       (FILE *)png_ptr->io_ptr);
    418 
    419    if (check != length)
    420    {
    421       png_error(png_ptr, "Read Error");
    422    }
    423 }
    424 
    425 static void
    426 png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
    427 {
    428    png_uint_32 check;
    429 
    430    check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
    431    if (check != length)
    432    {
    433       png_error(png_ptr, "Write Error");
    434    }
    435 }
    436 
    437 static void
    438 png_flush(png_structp png_ptr)
    439 {
    440    FILE *io_ptr;
    441    io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
    442    if (io_ptr != NULL)
    443       fflush(io_ptr);
    444 }
    445 
    446 #endif
    447 
    448 /*-----------------
    449  *  end of source
    450  *-----------------
    451  */
    452