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 #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 
     20 define_exception_type(const char *);
     21 extern struct exception_context the_exception_context[1];
     22 struct exception_context the_exception_context[1];
     23 png_const_charp msg;
     24 
     25 static OPENFILENAME ofn;
     26 
     27 static png_structp png_ptr = NULL;
     28 static png_infop info_ptr = NULL;
     29 
     30 
     31 // cexcept interface
     32 
     33 static void
     34 png_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 
     48 void 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 
     75 BOOL 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 
     85 BOOL 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 
     97 BOOL 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 
    287 BOOL 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 
    400 static void
    401 png_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 
    417 static void
    418 png_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 
    429 static void
    430 png_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