fukasawa e60969
/*---------------------------------------------------------------------------
fukasawa e60969
fukasawa e60969
   rpng2 - progressive-model PNG display program                 readpng2.c
fukasawa e60969
fukasawa e60969
  ---------------------------------------------------------------------------
fukasawa e60969
fukasawa e60969
      Copyright (c) 1998-2015 Greg Roelofs.  All rights reserved.
fukasawa e60969
fukasawa e60969
      This software is provided "as is," without warranty of any kind,
fukasawa e60969
      express or implied.  In no event shall the author or contributors
fukasawa e60969
      be held liable for any damages arising in any way from the use of
fukasawa e60969
      this software.
fukasawa e60969
fukasawa e60969
      The contents of this file are DUAL-LICENSED.  You may modify and/or
fukasawa e60969
      redistribute this software according to the terms of one of the
fukasawa e60969
      following two licenses (at your option):
fukasawa e60969
fukasawa e60969
fukasawa e60969
      LICENSE 1 ("BSD-like with advertising clause"):
fukasawa e60969
fukasawa e60969
      Permission is granted to anyone to use this software for any purpose,
fukasawa e60969
      including commercial applications, and to alter it and redistribute
fukasawa e60969
      it freely, subject to the following restrictions:
fukasawa e60969
fukasawa e60969
      1. Redistributions of source code must retain the above copyright
fukasawa e60969
         notice, disclaimer, and this list of conditions.
fukasawa e60969
      2. Redistributions in binary form must reproduce the above copyright
fukasawa e60969
         notice, disclaimer, and this list of conditions in the documenta-
fukasawa e60969
         tion and/or other materials provided with the distribution.
fukasawa e60969
      3. All advertising materials mentioning features or use of this
fukasawa e60969
         software must display the following acknowledgment:
fukasawa e60969
fukasawa e60969
            This product includes software developed by Greg Roelofs
fukasawa e60969
            and contributors for the book, "PNG: The Definitive Guide,"
fukasawa e60969
            published by O'Reilly and Associates.
fukasawa e60969
fukasawa e60969
fukasawa e60969
      LICENSE 2 (GNU GPL v2 or later):
fukasawa e60969
fukasawa e60969
      This program is free software; you can redistribute it and/or modify
fukasawa e60969
      it under the terms of the GNU General Public License as published by
fukasawa e60969
      the Free Software Foundation; either version 2 of the License, or
fukasawa e60969
      (at your option) any later version.
fukasawa e60969
fukasawa e60969
      This program is distributed in the hope that it will be useful,
fukasawa e60969
      but WITHOUT ANY WARRANTY; without even the implied warranty of
fukasawa e60969
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
fukasawa e60969
      GNU General Public License for more details.
fukasawa e60969
fukasawa e60969
      You should have received a copy of the GNU General Public License
fukasawa e60969
      along with this program; if not, write to the Free Software Foundation,
fukasawa e60969
      Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
fukasawa e60969
fukasawa e60969
  ---------------------------------------------------------------------------
fukasawa e60969
fukasawa e60969
   Changelog:
fukasawa e60969
     %RDATE% - Check return value of png_get_bKGD() (Glenn R-P)
fukasawa e60969
fukasawa e60969
  ---------------------------------------------------------------------------*/
fukasawa e60969
fukasawa e60969
fukasawa e60969
#include <stdlib.h>     /* for exit() prototype */</stdlib.h>
fukasawa e60969
#include <setjmp.h></setjmp.h>
fukasawa e60969
fukasawa e60969
#include <zlib.h></zlib.h>
fukasawa e60969
#include "png.h"        /* libpng header from the local directory */
fukasawa e60969
#include "readpng2.h"   /* typedefs, common macros, public prototypes */
fukasawa e60969
fukasawa e60969
fukasawa e60969
/* local prototypes */
fukasawa e60969
fukasawa e60969
static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr);
fukasawa e60969
static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row,
fukasawa e60969
                                 png_uint_32 row_num, int pass);
fukasawa e60969
static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr);
fukasawa e60969
static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg);
fukasawa e60969
static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg);
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
void readpng2_version_info(void)
fukasawa e60969
{
fukasawa e60969
    fprintf(stderr, "   Compiled with libpng %s; using libpng %s\n",
fukasawa e60969
      PNG_LIBPNG_VER_STRING, png_libpng_ver);
fukasawa e60969
fukasawa e60969
    fprintf(stderr, "   and with zlib %s; using zlib %s.\n",
fukasawa e60969
      ZLIB_VERSION, zlib_version);
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
int readpng2_check_sig(uch *sig, int num)
fukasawa e60969
{
fukasawa e60969
    return !png_sig_cmp(sig, 0, num);
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
/* returns 0 for success, 2 for libpng problem, 4 for out of memory */
fukasawa e60969
fukasawa e60969
int readpng2_init(mainprog_info *mainprog_ptr)
fukasawa e60969
{
fukasawa e60969
    png_structp  png_ptr;       /* note:  temporary variables! */
fukasawa e60969
    png_infop  info_ptr;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* could also replace libpng warning-handler (final NULL), but no need: */
fukasawa e60969
fukasawa e60969
    png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), mainprog_ptr,
fukasawa e60969
      readpng2_error_handler, readpng2_warning_handler);
fukasawa e60969
    if (!png_ptr)
fukasawa e60969
        return 4;   /* out of memory */
fukasawa e60969
fukasawa e60969
    info_ptr = png_create_info_struct(png_ptr);
fukasawa e60969
    if (!info_ptr) {
fukasawa e60969
        png_destroy_read_struct(&png_ptr, NULL, NULL);
fukasawa e60969
        return 4;   /* out of memory */
fukasawa e60969
    }
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* we could create a second info struct here (end_info), but it's only
fukasawa e60969
     * useful if we want to keep pre- and post-IDAT chunk info separated
fukasawa e60969
     * (mainly for PNG-aware image editors and converters) */
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* setjmp() must be called in every function that calls a PNG-reading
fukasawa e60969
     * libpng function, unless an alternate error handler was installed--
fukasawa e60969
     * but compatible error handlers must either use longjmp() themselves
fukasawa e60969
     * (as in this program) or exit immediately, so here we are: */
fukasawa e60969
fukasawa e60969
    if (setjmp(mainprog_ptr->jmpbuf)) {
fukasawa e60969
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fukasawa e60969
        return 2;
fukasawa e60969
    }
fukasawa e60969
fukasawa e60969
fukasawa e60969
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
fukasawa e60969
    /* prepare the reader to ignore all recognized chunks whose data won't be
fukasawa e60969
     * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT,
fukasawa e60969
     * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */
fukasawa e60969
    {
fukasawa e60969
        /* These byte strings were copied from png.h.  If a future version
fukasawa e60969
         * of readpng2.c recognizes more chunks, add them to this list.
fukasawa e60969
         */
fukasawa e60969
        static PNG_CONST png_byte chunks_to_process[] = {
fukasawa e60969
            98,  75,  71,  68, '\0',  /* bKGD */
fukasawa e60969
           103,  65,  77,  65, '\0',  /* gAMA */
fukasawa e60969
           115,  82,  71,  66, '\0',  /* sRGB */
fukasawa e60969
           };
fukasawa e60969
fukasawa e60969
       /* Ignore all chunks except for IHDR, PLTE, tRNS, IDAT, and IEND */
fukasawa e60969
       png_set_keep_unknown_chunks(png_ptr, -1 /* PNG_HANDLE_CHUNK_NEVER */,
fukasawa e60969
          NULL, -1);
fukasawa e60969
fukasawa e60969
       /* But do not ignore chunks in the "chunks_to_process" list */
fukasawa e60969
       png_set_keep_unknown_chunks(png_ptr,
fukasawa e60969
          0 /* PNG_HANDLE_CHUNK_AS_DEFAULT */, chunks_to_process,
fukasawa e60969
          sizeof(chunks_to_process)/5);
fukasawa e60969
    }
fukasawa e60969
#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* instead of doing png_init_io() here, now we set up our callback
fukasawa e60969
     * functions for progressive decoding */
fukasawa e60969
fukasawa e60969
    png_set_progressive_read_fn(png_ptr, mainprog_ptr,
fukasawa e60969
      readpng2_info_callback, readpng2_row_callback, readpng2_end_callback);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* make sure we save our pointers for use in readpng2_decode_data() */
fukasawa e60969
fukasawa e60969
    mainprog_ptr->png_ptr = png_ptr;
fukasawa e60969
    mainprog_ptr->info_ptr = info_ptr;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* and that's all there is to initialization */
fukasawa e60969
fukasawa e60969
    return 0;
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
/* returns 0 for success, 2 for libpng (longjmp) problem */
fukasawa e60969
fukasawa e60969
int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length)
fukasawa e60969
{
fukasawa e60969
    png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
fukasawa e60969
    png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* setjmp() must be called in every function that calls a PNG-reading
fukasawa e60969
     * libpng function */
fukasawa e60969
fukasawa e60969
    if (setjmp(mainprog_ptr->jmpbuf)) {
fukasawa e60969
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fukasawa e60969
        mainprog_ptr->png_ptr = NULL;
fukasawa e60969
        mainprog_ptr->info_ptr = NULL;
fukasawa e60969
        return 2;
fukasawa e60969
    }
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* hand off the next chunk of input data to libpng for decoding */
fukasawa e60969
fukasawa e60969
    png_process_data(png_ptr, info_ptr, rawbuf, length);
fukasawa e60969
fukasawa e60969
    return 0;
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr)
fukasawa e60969
{
fukasawa e60969
    mainprog_info  *mainprog_ptr;
fukasawa e60969
    int  color_type, bit_depth;
fukasawa e60969
    png_uint_32 width, height;
fukasawa e60969
#ifdef PNG_FLOATING_POINT_SUPPORTED
fukasawa e60969
    double  gamma;
fukasawa e60969
#else
fukasawa e60969
    png_fixed_point gamma;
fukasawa e60969
#endif
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* setjmp() doesn't make sense here, because we'd either have to exit(),
fukasawa e60969
     * longjmp() ourselves, or return control to libpng, which doesn't want
fukasawa e60969
     * to see us again.  By not doing anything here, libpng will instead jump
fukasawa e60969
     * to readpng2_decode_data(), which can return an error value to the main
fukasawa e60969
     * program. */
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* retrieve the pointer to our special-purpose struct, using the png_ptr
fukasawa e60969
     * that libpng passed back to us (i.e., not a global this time--there's
fukasawa e60969
     * no real difference for a single image, but for a multithreaded browser
fukasawa e60969
     * decoding several PNG images at the same time, one needs to avoid mixing
fukasawa e60969
     * up different images' structs) */
fukasawa e60969
fukasawa e60969
    mainprog_ptr = png_get_progressive_ptr(png_ptr);
fukasawa e60969
fukasawa e60969
    if (mainprog_ptr == NULL) {         /* we be hosed */
fukasawa e60969
        fprintf(stderr,
fukasawa e60969
          "readpng2 error:  main struct not recoverable in info_callback.\n");
fukasawa e60969
        fflush(stderr);
fukasawa e60969
        return;
fukasawa e60969
        /*
fukasawa e60969
         * Alternatively, we could call our error-handler just like libpng
fukasawa e60969
         * does, which would effectively terminate the program.  Since this
fukasawa e60969
         * can only happen if png_ptr gets redirected somewhere odd or the
fukasawa e60969
         * main PNG struct gets wiped, we're probably toast anyway.  (If
fukasawa e60969
         * png_ptr itself is NULL, we would not have been called.)
fukasawa e60969
         */
fukasawa e60969
    }
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* this is just like in the non-progressive case */
fukasawa e60969
fukasawa e60969
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
fukasawa e60969
       NULL, NULL, NULL);
fukasawa e60969
    mainprog_ptr->width = (ulg)width;
fukasawa e60969
    mainprog_ptr->height = (ulg)height;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* since we know we've read all of the PNG file's "header" (i.e., up
fukasawa e60969
     * to IDAT), we can check for a background color here */
fukasawa e60969
fukasawa e60969
    if (mainprog_ptr->need_bgcolor)
fukasawa e60969
    {
fukasawa e60969
        png_color_16p pBackground;
fukasawa e60969
fukasawa e60969
        /* it is not obvious from the libpng documentation, but this function
fukasawa e60969
         * takes a pointer to a pointer, and it always returns valid red,
fukasawa e60969
         * green and blue values, regardless of color_type: */
fukasawa e60969
        if (png_get_bKGD(png_ptr, info_ptr, &pBackground))
fukasawa e60969
        {
fukasawa e60969
fukasawa e60969
           /* however, it always returns the raw bKGD data, regardless of any
fukasawa e60969
            * bit-depth transformations, so check depth and adjust if necessary
fukasawa e60969
            */
fukasawa e60969
           if (bit_depth == 16) {
fukasawa e60969
               mainprog_ptr->bg_red   = pBackground->red   >> 8;
fukasawa e60969
               mainprog_ptr->bg_green = pBackground->green >> 8;
fukasawa e60969
               mainprog_ptr->bg_blue  = pBackground->blue  >> 8;
fukasawa e60969
           } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
fukasawa e60969
               if (bit_depth == 1)
fukasawa e60969
                   mainprog_ptr->bg_red = mainprog_ptr->bg_green =
fukasawa e60969
                     mainprog_ptr->bg_blue = pBackground->gray? 255 : 0;
fukasawa e60969
               else if (bit_depth == 2)
fukasawa e60969
                   mainprog_ptr->bg_red = mainprog_ptr->bg_green =
fukasawa e60969
                     mainprog_ptr->bg_blue = (255/3) * pBackground->gray;
fukasawa e60969
               else /* bit_depth == 4 */
fukasawa e60969
                   mainprog_ptr->bg_red = mainprog_ptr->bg_green =
fukasawa e60969
                     mainprog_ptr->bg_blue = (255/15) * pBackground->gray;
fukasawa e60969
           } else {
fukasawa e60969
               mainprog_ptr->bg_red   = (uch)pBackground->red;
fukasawa e60969
               mainprog_ptr->bg_green = (uch)pBackground->green;
fukasawa e60969
               mainprog_ptr->bg_blue  = (uch)pBackground->blue;
fukasawa e60969
           }
fukasawa e60969
        }
fukasawa e60969
    }
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* as before, let libpng expand palette images to RGB, low-bit-depth
fukasawa e60969
     * grayscale images to 8 bits, transparency chunks to full alpha channel;
fukasawa e60969
     * strip 16-bit-per-sample images to 8 bits per sample; and convert
fukasawa e60969
     * grayscale to RGB[A] */
fukasawa e60969
fukasawa e60969
    if (color_type == PNG_COLOR_TYPE_PALETTE)
fukasawa e60969
        png_set_expand(png_ptr);
fukasawa e60969
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
fukasawa e60969
        png_set_expand(png_ptr);
fukasawa e60969
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
fukasawa e60969
        png_set_expand(png_ptr);
fukasawa e60969
#ifdef PNG_READ_16_TO_8_SUPPORTED
fukasawa e60969
    if (bit_depth == 16)
fukasawa e60969
#  ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
fukasawa e60969
        png_set_scale_16(png_ptr);
fukasawa e60969
#  else
fukasawa e60969
        png_set_strip_16(png_ptr);
fukasawa e60969
#  endif
fukasawa e60969
#endif
fukasawa e60969
    if (color_type == PNG_COLOR_TYPE_GRAY ||
fukasawa e60969
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
fukasawa e60969
        png_set_gray_to_rgb(png_ptr);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* Unlike the basic viewer, which was designed to operate on local files,
fukasawa e60969
     * this program is intended to simulate a web browser--even though we
fukasawa e60969
     * actually read from a local file, too.  But because we are pretending
fukasawa e60969
     * that most of the images originate on the Internet, we follow the recom-
fukasawa e60969
     * mendation of the sRGB proposal and treat unlabelled images (no gAMA
fukasawa e60969
     * chunk) as existing in the sRGB color space.  That is, we assume that
fukasawa e60969
     * such images have a file gamma of 0.45455, which corresponds to a PC-like
fukasawa e60969
     * display system.  This change in assumptions will have no effect on a
fukasawa e60969
     * PC-like system, but on a Mac, SGI, NeXT or other system with a non-
fukasawa e60969
     * identity lookup table, it will darken unlabelled images, which effec-
fukasawa e60969
     * tively favors images from PC-like systems over those originating on
fukasawa e60969
     * the local platform.  Note that mainprog_ptr->display_exponent is the
fukasawa e60969
     * "gamma" value for the entire display system, i.e., the product of
fukasawa e60969
     * LUT_exponent and CRT_exponent. */
fukasawa e60969
fukasawa e60969
#ifdef PNG_FLOATING_POINT_SUPPORTED
fukasawa e60969
    if (png_get_gAMA(png_ptr, info_ptr, &gamma))
fukasawa e60969
        png_set_gamma(png_ptr, mainprog_ptr->display_exponent, gamma);
fukasawa e60969
    else
fukasawa e60969
        png_set_gamma(png_ptr, mainprog_ptr->display_exponent, 0.45455);
fukasawa e60969
#else
fukasawa e60969
    if (png_get_gAMA_fixed(png_ptr, info_ptr, &gamma))
fukasawa e60969
        png_set_gamma_fixed(png_ptr,
fukasawa e60969
            (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), gamma);
fukasawa e60969
    else
fukasawa e60969
        png_set_gamma_fixed(png_ptr,
fukasawa e60969
            (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), 45455);
fukasawa e60969
#endif
fukasawa e60969
fukasawa e60969
    /* we'll let libpng expand interlaced images, too */
fukasawa e60969
fukasawa e60969
    mainprog_ptr->passes = png_set_interlace_handling(png_ptr);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* all transformations have been registered; now update info_ptr data and
fukasawa e60969
     * then get rowbytes and channels */
fukasawa e60969
fukasawa e60969
    png_read_update_info(png_ptr, info_ptr);
fukasawa e60969
fukasawa e60969
    mainprog_ptr->rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr);
fukasawa e60969
    mainprog_ptr->channels = png_get_channels(png_ptr, info_ptr);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* Call the main program to allocate memory for the image buffer and
fukasawa e60969
     * initialize windows and whatnot.  (The old-style function-pointer
fukasawa e60969
     * invocation is used for compatibility with a few supposedly ANSI
fukasawa e60969
     * compilers that nevertheless barf on "fn_ptr()"-style syntax.) */
fukasawa e60969
fukasawa e60969
    (*mainprog_ptr->mainprog_init)();
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* and that takes care of initialization */
fukasawa e60969
fukasawa e60969
    return;
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row,
fukasawa e60969
                                  png_uint_32 row_num, int pass)
fukasawa e60969
{
fukasawa e60969
    mainprog_info  *mainprog_ptr;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* first check whether the row differs from the previous pass; if not,
fukasawa e60969
     * nothing to combine or display */
fukasawa e60969
fukasawa e60969
    if (!new_row)
fukasawa e60969
        return;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* retrieve the pointer to our special-purpose struct so we can access
fukasawa e60969
     * the old rows and image-display callback function */
fukasawa e60969
fukasawa e60969
    mainprog_ptr = png_get_progressive_ptr(png_ptr);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* save the pass number for optional use by the front end */
fukasawa e60969
fukasawa e60969
    mainprog_ptr->pass = pass;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* have libpng either combine the new row data with the existing row data
fukasawa e60969
     * from previous passes (if interlaced) or else just copy the new row
fukasawa e60969
     * into the main program's image buffer */
fukasawa e60969
fukasawa e60969
    png_progressive_combine_row(png_ptr, mainprog_ptr->row_pointers[row_num],
fukasawa e60969
      new_row);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* finally, call the display routine in the main program with the number
fukasawa e60969
     * of the row we just updated */
fukasawa e60969
fukasawa e60969
    (*mainprog_ptr->mainprog_display_row)(row_num);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* and we're ready for more */
fukasawa e60969
fukasawa e60969
    return;
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr)
fukasawa e60969
{
fukasawa e60969
    mainprog_info  *mainprog_ptr;
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* retrieve the pointer to our special-purpose struct */
fukasawa e60969
fukasawa e60969
    mainprog_ptr = png_get_progressive_ptr(png_ptr);
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* let the main program know that it should flush any buffered image
fukasawa e60969
     * data to the display now and set a "done" flag or whatever, but note
fukasawa e60969
     * that it SHOULD NOT DESTROY THE PNG STRUCTS YET--in other words, do
fukasawa e60969
     * NOT call readpng2_cleanup() either here or in the finish_display()
fukasawa e60969
     * routine; wait until control returns to the main program via
fukasawa e60969
     * readpng2_decode_data() */
fukasawa e60969
fukasawa e60969
    (*mainprog_ptr->mainprog_finish_display)();
fukasawa e60969
fukasawa e60969
fukasawa e60969
    /* all done */
fukasawa e60969
fukasawa e60969
    (void)info_ptr; /* Unused */
fukasawa e60969
fukasawa e60969
    return;
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
fukasawa e60969
void readpng2_cleanup(mainprog_info *mainprog_ptr)
fukasawa e60969
{
fukasawa e60969
    png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
fukasawa e60969
    png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
fukasawa e60969
fukasawa e60969
    if (png_ptr && info_ptr)
fukasawa e60969
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fukasawa e60969
fukasawa e60969
    mainprog_ptr->png_ptr = NULL;
fukasawa e60969
    mainprog_ptr->info_ptr = NULL;
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg)
fukasawa e60969
{
fukasawa e60969
    fprintf(stderr, "readpng2 libpng warning: %s\n", msg);
fukasawa e60969
    fflush(stderr);
fukasawa e60969
    (void)png_ptr; /* Unused */
fukasawa e60969
}
fukasawa e60969
fukasawa e60969
fukasawa e60969
static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg)
fukasawa e60969
{
fukasawa e60969
    mainprog_info  *mainprog_ptr;
fukasawa e60969
fukasawa e60969
    /* This function, aside from the extra step of retrieving the "error
fukasawa e60969
     * pointer" (below) and the fact that it exists within the application
fukasawa e60969
     * rather than within libpng, is essentially identical to libpng's
fukasawa e60969
     * default error handler.  The second point is critical:  since both
fukasawa e60969
     * setjmp() and longjmp() are called from the same code, they are
fukasawa e60969
     * guaranteed to have compatible notions of how big a jmp_buf is,
fukasawa e60969
     * regardless of whether _BSD_SOURCE or anything else has (or has not)
fukasawa e60969
     * been defined. */
fukasawa e60969
fukasawa e60969
    fprintf(stderr, "readpng2 libpng error: %s\n", msg);
fukasawa e60969
    fflush(stderr);
fukasawa e60969
fukasawa e60969
    mainprog_ptr = png_get_error_ptr(png_ptr);
fukasawa e60969
    if (mainprog_ptr == NULL) {         /* we are completely hosed now */
fukasawa e60969
        fprintf(stderr,
fukasawa e60969
          "readpng2 severe error:  jmpbuf not recoverable; terminating.\n");
fukasawa e60969
        fflush(stderr);
fukasawa e60969
        exit(99);
fukasawa e60969
    }
fukasawa e60969
fukasawa e60969
    /* Now we have our data structure we can use the information in it
fukasawa e60969
     * to return control to our own higher level code (all the points
fukasawa e60969
     * where 'setjmp' is called in this file.)  This will work with other
fukasawa e60969
     * error handling mechanisms as well - libpng always calls png_error
fukasawa e60969
     * when it can proceed no further, thus, so long as the error handler
fukasawa e60969
     * is intercepted, application code can do its own error recovery.
fukasawa e60969
     */
fukasawa e60969
    longjmp(mainprog_ptr->jmpbuf, 1);
fukasawa e60969
}