--- /dev/null
+
+Libpng 1.0.3 - January 14, 1999
+
+This is a public release of libpng, intended for use in production codes.
+
+Changes since the previous public release (1.0.2):
+
+libpng-1.0.3:
+
+ Replaced and extended code that was removed from png_set_filler() in 1.0.1a.
+ Fixed a bug in png_do_filler() that made it fail to write filler bytes in
+ the left-most pixel of each row (Kevin Bracey).
+ Changed "static pngcharp tIME_string" to "static char tIME_string[30]"
+ in pngtest.c (Duncan Simpson).
+ Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk
+ even when no tIME chunk was present in the source file.
+ Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit.
+ Fixed a problem in png_read_push_finish_row(), which would not skip some
+ passes that it should skip, for images that are less than 3 pixels high.
+ Interchanged the order of calls to png_do_swap() and png_do_shift()
+ in pngwtran.c (John Cromer).
+ Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h .
+ Changed "bad adaptive filter type" from error to warning in pngrutil.c .
+ Fixed a documentation error about default filtering with 8-bit indexed-color.
+ Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO
+ (L. Peter Deutsch).
+ Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions.
+ Added png_get_copyright() and png_get_header_version() functions.
+ Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c
+ Added information about debugging in libpng.txt and libpng.3 .
+ Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco.
+ Removed lines after Dynamic Dependencies" in makefile.aco .
+ Revised makefile.dec to make a shared library (Jeremie Petit).
+ Removed trailing blanks from all files.
+ Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h
+ Added "if" tests to silence complaints about unused png_ptr in png.h and png.c
+ Changed "check_if_png" function in example.c to return true (nonzero) if PNG.
+ Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig()
+ which is obsolete.
+ Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice)
+ Added a statement of Y2K compliance in png.h, libpng.1, and Y2KINFO.
+
+Send comments/corrections/commendations to
+png-implement@dworkin.wustl.edu or to randeg@alumni.rpi.edu
+
+Glenn R-P
+
+Send comments/corrections/commendations to
+png-implement@dworkin.wustl.edu or to randeg@alumni.rpi.edu
+
+Glenn Randers-Pehrson
+libpng maintainer
+PNG Development Group
--- /dev/null
+CHANGES - changes for libpng
+
+version 0.2
+ added reader into png.h
+ fixed small problems in stub file
+version 0.3
+ added pull reader
+ split up pngwrite.c to several files
+ added pnglib.txt
+ added example.c
+ cleaned up writer, adding a few new tranformations
+ fixed some bugs in writer
+ interfaced with zlib 0.5
+ added K&R support
+ added check for 64 KB blocks for 16 bit machines
+version 0.4
+ cleaned up code and commented code
+ simplified time handling into png_time
+ created png_color_16 and png_color_8 to handle color needs
+ cleaned up color type defines
+ fixed various bugs
+ made various names more consistant
+ interfaced with zlib 0.71
+ cleaned up zTXt reader and writer (using zlib's Reset functions)
+ split transformations into pngrtran.c and pngwtran.c
+version 0.5
+ interfaced with zlib 0.8
+ fixed many reading and writing bugs
+ saved using 3 spaces instead of tabs
+version 0.6
+ added png_large_malloc() and png_large_free()
+ added png_size_t
+ cleaned up some compiler warnings
+ added png_start_read_image()
+version 0.7
+ cleaned up lots of bugs
+ finished dithering and other stuff
+ added test program
+ changed name from pnglib to libpng
+version 0.71 [June, 1995]
+ changed pngtest.png for zlib 0.93
+ fixed error in libpng.txt and example.c
+version 0.8
+ cleaned up some bugs
+ added png_set_filler()
+ split up pngstub.c into pngmem.c, pngio.c, and pngerror.c
+ added #define's to remove unwanted code
+ moved png_info_init() to png.c
+ added old_size into png_realloc()
+ added functions to manually set filtering and compression info
+ changed compression parameters based on image type
+ optimized filter selection code
+ added version info
+ changed external functions passing floats to doubles (k&r problems?)
+ put all the configurable stuff in pngconf.h
+ enabled png_set_shift to work with paletted images on read
+ added png_read_update_info() - updates info structure with
+ transformations
+version 0.81 [August, 1995]
+ incorporated Tim Wegner's medium model code (thanks, Tim)
+version 0.82 [September, 1995]
+ [unspecified changes]
+version 0.85 [December, 1995]
+ added more medium model code (almost everything's a far)
+ added i/o, error, and memory callback functions
+ fixed some bugs (16 bit, 4 bit interlaced, etc.)
+ added first run progressive reader (barely tested)
+version 0.86 [January, 1996]
+ fixed bugs
+ improved documentation
+version 0.87 [January, 1996]
+ fixed medium model bugs
+ fixed other bugs introduced in 0.85 and 0.86
+ added some minor documentation
+version 0.88 [January, 1996]
+ fixed progressive bugs
+ replaced tabs with spaces
+ cleaned up documentation
+ added callbacks for read/write and warning/error functions
+version 0.89 [July, 1996]
+ added new initialization API to make libpng work better with shared libs
+ we now have png_create_read_struct(), png_create_write_struct(),
+ png_create_info_struct(), png_destroy_read_struct(), and
+ png_destroy_write_struct() instead of the separate calls to
+ malloc and png_read_init(), png_info_init(), and png_write_init()
+ changed warning/error callback functions to fix bug - this means you
+ should use the new initialization API if you were using the old
+ png_set_message_fn() calls, and that the old API no longer exists
+ so that people are aware that they need to change their code
+ changed filter selection API to allow selection of multiple filters
+ since it didn't work in previous versions of libpng anyways
+ optimized filter selection code
+ fixed png_set_background() to allow using an arbitrary RGB color for
+ paletted images
+ fixed gamma and background correction for paletted images, so
+ png_correct_palette is not needed unless you are correcting an
+ external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED
+ in pngconf.h) - if nobody uses this, it may disappear in the future.
+ fixed bug with Borland 64K memory allocation (Alexander Lehmann)
+ fixed bug in interlace handling (Smarasderagd, I think)
+ added more error checking for writing and image to reduce invalid files
+ separated read and write functions so that they won't both be linked
+ into a binary when only reading or writing functionality is used
+ new pngtest image also has interlacing and zTXt
+ updated documentation to reflect new API
+version 0.90 [January, 1997]
+ made CRC errors/warnings on critical and ancillary chunks configurable
+ libpng will use the zlib CRC routines by (compile-time) default
+ changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner)
+ added external C++ wrapper statements to png.h (Gilles Dauphin)
+ allow PNG file to be read when some or all of file signature has already
+ been read from the beginning of the stream. ****This affects the size
+ of info_struct and invalidates all programs that use a shared libpng****
+ fixed png_filler() declarations
+ fixed? background color conversions
+ fixed order of error function pointers to match documentation
+ current chunk name is now available in png_struct to reduce the number
+ of nearly identical error messages (will simplify multi-lingual
+ support when available)
+ try to get ready for unknown-chunk callback functions:
+ - previously read critical chunks are flagged, so the chunk handling
+ routines can determine if the chunk is in the right place
+ - all chunk handling routines have the same prototypes, so we will
+ be able to handle all chunks via a callback mechanism
+ try to fix Linux "setjmp" buffer size problems
+version 0.95 [March, 1997]
+ fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never
+ fixed bug in PNG file signature compares when start != 0
+ changed parameter type of png_set_filler(...filler...) from png_byte
+ to png_uint_32
+ added test for MACOS to ensure that both math.h and fp.h are not #included
+ added macros for libpng to be compiled as a Windows DLL (Andreas Kupries)
+ added "packswap" transformation, which changes the endianness of
+ packed-pixel bytes (Kevin Bracey)
+ added "strip_alpha" transformation, which removes the alpha channel of
+ input images without using it (not neccesarily a good idea)
+ added "swap_alpha" transformation, which puts the alpha channel in front
+ of the color bytes instead of after
+ removed all implicit variable tests which assume NULL == 0 (I think)
+ changed several variables to "png_size_t" to show 16/32-bit limitations
+ added new pCAL chunk read/write support
+ added experimental filter selection weighting (Greg Roelofs)
+ removed old png_set_rgbx() and png_set_xrgb() functions that have been
+ obsolete for about 2 years now (use png_set_filler() instead)
+ added macros to read 16- and 32-bit ints directly from buffer, to be
+ used only on those systems that support it (namely PowerPC and 680x0)
+ With some testing, this may become the default for MACOS/PPC systems.
+ only calculate CRC on data if we are going to use it
+ added macros for zTXt compression type PNG_zTXt_COMPRESSION_???
+ added macros for simple libpng debugging output selectable at compile time
+ removed PNG_READ_END_MODE in progressive reader (Smarasderagd)
+ more description of info_struct in libpng.txt and png.h
+ more instructions in example.c
+ more chunk types tested in pngtest.c
+ renamed pngrcb.c to pngset.c, and all png_read_<chunk> functions to be
+ png_set_<chunk>. We now have corresponding png_get_<chunk>
+ functions in pngget.c to get infomation in info_ptr. This isolates
+ the application from the internal organization of png_info_struct
+ (good for shared library implementations).
+version 0.96 [May, 1997]
+ fixed serious bug with < 8bpp images introduced in 0.95
+ fixed 256-color transparency bug (Greg Roelofs)
+ fixed up documentation (Greg Roelofs, Laszlo Nyul)
+ fixed "error" in pngconf.h for Linux setjmp() behaviour
+ fixed DOS medium model support (Tim Wegner)
+ fixed png_check_keyword() for case with error in static string text
+ added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul)
+ added typecasts to quiet compiler errors
+ added more debugging info
+version 0.97 [January, 1998]
+ removed PNG_USE_OWN_CRC capability
+ relocated png_set_crc_action from pngrutil.c to pngrtran.c
+ fixed typecasts of "new_key", etc. (Andreas Dilger)
+ added RFC 1152 [sic] date support
+ fixed bug in gamma handling of 4-bit grayscale
+ added 2-bit grayscale gamma handling (Glenn R-P)
+ added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P)
+ minor corrections in libpng.txt
+ added simple sRGB support (Glenn R-P)
+ easier conditional compiling, e.g. define PNG_READ/WRITE_NOT_FULLY_SUPPORTED;
+ all configurable options can be selected from command-line instead
+ of having to edit pngconf.h (Glenn R-P)
+ fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P)
+ added more conditions for png_do_background, to avoid changing
+ black pixels to background when a background is supplied and
+ no pixels are transparent
+ repaired PNG_NO_STDIO behaviour
+ tested NODIV support and made it default behaviour (Greg Roelofs)
+ added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler)
+ regularized version numbering scheme and bumped shared-library major
+ version number to 2 to avoid problems with libpng 0.89 apps (Greg Roelofs)
+version 0.98 [January, 1998]
+ cleaned up some typos in libpng.txt and in code documentation
+ fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler)
+ cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c
+ changed recommendation about file_gamma for PC images to .51 from .45,
+ in example.c and libpng.txt, added comments to distinguish between
+ screen_gamma, viewing_gamma, and display_gamma.
+ changed all references to RFC1152 to read RFC1123 and changed the
+ PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED
+ added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent)
+ changed srgb_intent from png_byte to int to avoid compiler bugs
+version 0.99 [January 30, 1998]
+ free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler)
+ fixed a longstanding "packswap" bug in pngtrans.c
+ fixed some inconsistencies in pngconf.h that prevented compiling with
+ PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined
+ fixed some typos and made other minor rearrangement of libpng.txt (Andreas)
+ changed recommendation about file_gamma for PC images to .50 from .51 in
+ example.c and libpng.txt, and changed file_gamma for sRGB images to .45
+ added a number of functions to access information from the png structure
+ png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit)
+ added TARGET_MACOS similar to zlib-1.0.8
+ define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined
+ added type casting to all png_malloc() function calls
+version 0.99a [January 31, 1998]
+ Added type casts and parentheses to all returns that return a value.(Tim W.)
+version 0.99b [February 4, 1998]
+ Added type cast png_uint_32 on malloc function calls where needed.
+ Changed type of num_hist from png_uint_32 to int (same as num_palette).
+ Added checks for rowbytes overflow, in case png_size_t is less than 32 bits.
+ Renamed makefile.elf to makefile.lnx.
+version 0.99c [February 7, 1998]
+ More type casting. Removed erroneous overflow test in pngmem.c.
+ Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes.
+ Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5.
+version 0.99d [February 11, 1998]
+ Renamed "far_to_near()" "png_far_to_near()"
+ Revised libpng.3
+ Version 99c "buffered" operations didn't work as intended. Replaced them
+ with png_memcpy_check() and png_memset_check().
+ Added many "if (png_ptr == NULL) return" to quell compiler warnings about
+ unused png_ptr, mostly in pngget.c and pngset.c.
+ Check for overlength tRNS chunk present when indexed-color PLTE is read.
+ Cleaned up spelling errors in libpng.3/libpng.txt
+ Corrected a problem with png_get_tRNS() which returned undefined trans array
+version 0.99e [February 28, 1998]
+ Corrected png_get_tRNS() again.
+ Add parentheses for easier reading of pngget.c, fixed "||" should be "&&".
+ Touched up example.c to make more of it compileable, although the entire
+ file still can't be compiled (Willem van Schaik)
+ Fixed a bug in png_do_shift() (Bryan Tsai)
+ Added a space in png.h prototype for png_write_chunk_start()
+ Replaced pngtest.png with one created with zlib 1.1.1
+ Changed pngtest to report PASS even when file size is different (Jean-loup G.)
+ Corrected some logic errors in png_do_invert_alpha() (Chris Patterson)
+version 0.99f [March 5, 1998]
+ Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey)
+ Moved makefiles into a "scripts" directory, and added INSTALL instruction file
+ Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok)
+ Added pointers to "note on libpng versions" in makefile.lnx and README
+ Added row callback feature when reading and writing nonprogressive rows
+ and added a test of this feature in pngtest.c
+ Added user transform callbacks, with test of the feature in pngtest.c
+version 0.99g [March 6, 1998, morning]
+ Minor changes to pngtest.c to suppress compiler warnings.
+ Removed "beta" language from documentation.
+version 0.99h [March 6, 1998, evening]
+ Minor changes to previous minor changes to pngtest.c
+ Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED
+ and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro
+version 1.00 [March 7, 1998]
+ Changed several typedefs in pngrutil.c
+ Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik)
+ replaced "while(1)" with "for(;;)"
+ added PNGARG() to prototypes in pngtest.c and removed some prototypes
+ updated some of the makefiles (Tom Lane)
+ changed some typedefs (s_start, etc.) in pngrutil.c
+ fixed dimensions of "short_months" array in pngwrite.c
+ Replaced ansi2knr.c with the one from jpeg-v6
+version 1.0.0 [March 8, 1998]
+ Changed name from 1.00 to 1.0.0 (Adam Costello)
+ Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert)
+version 1.0.0a [March 9, 1998]
+ Fixed three bugs in pngrtran.c to make gamma+background handling consistent
+ (Greg Roelofs)
+ Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz
+ for major, minor, and bugfix releases. This is 10001. (Adam Costello,
+ Tom Lane)
+ Make months range from 1-12 in png_convert_to_rfc1123
+version 1.0.0b [March 13, 1998]
+ Quieted compiler complaints about two empty "for" loops in pngrutil.c
+ Minor changes to makefile.s2x
+ Removed #ifdef/#endif around a png_free() in pngread.c
+version 1.0.1 [March 14, 1998]
+ Changed makefile.s2x to reduce security risk of using a relative pathname
+ Fixed some typos in the documentation (Greg).
+ Fixed a problem with value of "channels" returned by png_read_update_info()
+version 1.0.1a [April 21, 1998]
+ Optimized Paeth calculations by replacing abs() function calls with intrinsics
+ plus other loop optimizations. Improves avg decoding speed by about 20%.
+ Commented out i386istic "align" compiler flags in makefile.lnx.
+ Reduced the default warning level in some makefiles, to make them consistent.
+ Removed references to IJG and JPEG in the ansi2knr.c copyright statement.
+ Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation.
+ Added grayscale and 16-bit capability to png_do_read_filler().
+ Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes
+ too large when writing an image with bit_depth < 8 (Bob Dellaca).
+ Corrected some bugs in the experimental weighted filtering heuristics.
+ Moved a misplaced pngrutil code block that truncates tRNS if it has more
+ than num_palette entries -- test was done before num_palette was defined.
+ Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins).
+ Changed compiler flags in makefile.wat for better optimization (Pawel Mrochen).
+version 1.0.1b [May 2, 1998]
+ Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg).
+ Relocated the png_composite macros from pngrtran.c to png.h (Greg).
+ Added makefile.sco (contributed by Mike Hopkirk).
+ Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a.
+ Fixed a bug in pngrtran.c that would set channels=5 under some circumstances.
+ More work on the Paeth-filtering, achieving imperceptible speedup (A Kleinert).
+ More work on loop optimization which may help when compiled with C++ compilers.
+ Added warnings when people try to use transforms they've defined out.
+ Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran.
+ Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg)
+version 1.0.1c [May 11, 1998]
+ Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for
+ filler bytes should have been 0xff instead of 0xf.
+ Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images.
+ Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED
+ out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h
+ Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED,
+ for consistency, in pngconf.h
+ Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier
+ to remove unwanted capabilities via the compile line
+ Made some corrections to grammar (which, it's) in documentation (Greg).
+ Corrected example.c, use of row_pointers in png_write_image().
+version 1.0.1d [May 24, 1998]
+ Corrected several statements that used side effects illegally in pngrutil.c
+ and pngtrans.c, that were introduced in version 1.0.1b
+ Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert)
+ More corrections to example.c, use of row_pointers in png_write_image()
+ and png_read_rows().
+ Added pngdll.mak and pngdef.pas to scripts directory, contributed by
+ Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5
+ Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.)
+ Changed several loops from count-down to count-up, for consistency.
+version 1.0.1e [June 6, 1998]
+ Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and
+ added warnings when people try to set png_read_fn and png_write_fn in
+ the same structure.
+ Added a test such that png_do_gamma will be done when num_trans==0
+ for truecolor images that have defined a background. This corrects an
+ error that was introduced in libpng-0.90 that can cause gamma processing
+ to be skipped.
+ Added tests in png.h to include "trans" and "trans_values" in structures
+ when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined.
+ Add png_free(png_ptr->time_buffer) in png_destroy_read_struct()
+ Moved png_convert_to_rfc_1123() from pngwrite.c to png.c
+ Added capability for user-provided malloc_fn() and free_fn() functions,
+ and revised pngtest.c to demonstrate their use, replacing the
+ PNGTEST_DEBUG_MEM feature.
+ Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner).
+version 1.0.2 [June 14, 1998]
+ Fixed two bugs in makefile.bor .
+version 1.0.2a [December 30, 1998]
+ Replaced and extended code that was removed from png_set_filler() in 1.0.1a.
+ Fixed a bug in png_do_filler() that made it fail to write filler bytes in
+ the left-most pixel of each row (Kevin Bracey).
+ Changed "static pngcharp tIME_string" to "static char tIME_string[30]"
+ in pngtest.c (Duncan Simpson).
+ Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk
+ even when no tIME chunk was present in the source file.
+ Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit.
+ Fixed a problem in png_read_push_finish_row(), which would not skip some
+ passes that it should skip, for images that are less than 3 pixels high.
+ Interchanged the order of calls to png_do_swap() and png_do_shift()
+ in pngwtran.c (John Cromer).
+ Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h .
+ Changed "bad adaptive filter type" from error to warning in pngrutil.c .
+ Fixed a documentation error about default filtering with 8-bit indexed-color.
+ Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO
+ (L. Peter Deutsch).
+ Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions.
+ Added png_get_copyright() and png_get_header_version() functions.
+ Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c
+ Added information about debugging in libpng.txt and libpng.3 .
+ Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco.
+ Removed lines after Dynamic Dependencies" in makefile.aco .
+ Revised makefile.dec to make a shared library (Jeremie Petit).
+ Removed trailing blanks from all files.
+version 1.0.2a [January 6, 1999]
+ Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h
+ Added "if" tests to silence complaints about unused png_ptr in png.h and png.c
+ Changed "check_if_png" function in example.c to return true (nonzero) if PNG.
+ Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig()
+ which is obsolete.
+version 1.0.3 [January 14, 1999]
+ Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice)
+ Added a statement of Y2K compliance in png.h, libpng.1, and Y2KINFO.
--- /dev/null
+
+Installing libpng version 1.0.3 - January 14, 1999
+
+Before installing libpng, you must first install zlib. zlib
+can usually be found wherever you got libpng. zlib can be
+placed in another directory, at the same level as libpng.
+Note that your system might already have a preinstalled
+zlib, but you will still need to have access to the
+zlib.h and zconf.h include files that correspond to the
+version of zlib that's installed.
+
+You can rename the directories that you downloaded (they
+might be called "libpng-1.0.3" or "lpng103" and "zlib-1.1.3"
+or "zlib113") so that you have directories called "zlib" and "libpng".
+
+Your directory structure should look like this:
+
+ .. (the parent directory)
+ libpng (this directory)
+ INSTALL (this file)
+ README
+ *.h
+ *.c
+ scripts
+ makefile.*
+ pngtest.png
+ etc.
+ zlib
+ README
+ *.h
+ *.c
+ contrib
+ etc.
+
+First enter the zlib directory and follow the instructions
+in zlib/README. Then come back here and choose the
+appropriate makefile.sys in the scripts directory.
+The files that are presently available in the scripts directory
+include
+
+ descrip.mms => VMS makefile for MMS or MMK
+ makefile.std => Generic UNIX makefile
+ makefile.knr => Archaic UNIX Makefile that converts files with ansi2knr
+ makefile.dec => DEC Alpha UNIX makefile
+ makefile.hux => HPUX (10.20 and 11.00) makefile
+ makefile.sgi => Silicon Graphics IRIX makefile
+ makefile.sun => Sun makefile
+ makefile.s2x => Solaris 2.X makefile (gcc, creates libpng.so.2.1.0)
+ makefile.lnx => Linux/ELF makefile (gcc, creates libpng.so.2.1.0)
+ makefile.mip => MIPS makefile
+ makefile.aco => Acorn makefile
+ makefile.ama => Amiga makefile
+ smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC compiler
+ (Requires SCOPTIONS, copied from scripts/SCOPTIONS.ppc)
+ makefile.atr => Atari makefile
+ makefile.bor => Borland makefile
+ build.bat => MS-DOS batch file for Borland compiler
+ makefile.dj2 => DJGPP 2 makefile
+ makefile.msc => Microsoft C makefile
+ makefile.w32 => makefile for Microsoft Visual C++ 4.0 and later
+ makefile.tc3 => Turbo C 3.0 makefile
+ makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def)
+ pngos2.def => OS/2 module definition file used by makefile.os2
+ makefile.wat => Watcom 10a+ Makefile, 32-bit flat memory model
+ makevms.com => VMS build script
+ pngdll.mak => To make a png32bd.dll with Borland C++ 4.5
+ pngdef.pas => Defines for a png32bd.dll with Borland C++ 4.5
+
+Copy the file (or files) that you need from the
+scripts directory into this directory, for example
+
+ MSDOS example: copy scripts\makefile.msd makefile
+ UNIX example: cp scripts/makefile.std makefile
+
+Read the makefile to see if you need to change any source or
+target directories to match your preferences.
+
+Then read pngconf.h to see if you want to make any configuration
+changes.
+
+Then just run "make test" which will create the libpng library in
+this directory and run a quick test that reads the "pngtest.png"
+file and writes a "pngout.png" file that should be identical to it.
+
+Most of the makefiles will allow you to run "make install" to
+put the library in its final resting place (if you want to
+do that, run "make install" in the zlib directory first if necessary).
+
+Further information can be found in the README and libpng.txt
+files, in the individual makefiles, and in png.h, and the manual
+pages libpng.3 and png.5.
--- /dev/null
+README for libpng 1.0.3 - January 14, 1999 (shared library 2.1)
+See the note about version numbers near the top of png.h
+
+See INSTALL for instructions on how to install libpng.
+
+This is the first official release of libpng. Don't let the fact that
+it's the first release fool you. The libpng library has been in
+extensive use and testing for about two and a half years. However, it's
+finally gotten to the stage where there haven't been significant
+changes to the API in some time, and people have a bad feeling about
+libraries with versions < 1.0.
+
+****
+Note that some of the changes to the png_info structure render this
+version of the library binary incompatible with libpng-0.89 or
+earlier versions if you are using a shared library. The type of the
+"filler" parameter for png_set_filler() has changed from png_byte to
+png_uint_32, which will affect shared-library applications that use
+this function.
+
+To avoid problems with changes to the internals of png_info_struct,
+new APIs have been made available in 0.95 to avoid direct application
+access to info_ptr. These functions are the png_set_<chunk> and
+png_get_<chunk> functions. These functions should be used when
+accessing/storing the info_struct data, rather than manipulating it
+directly, to avoid such problems in the future.
+
+It is important to note that the APIs do not make current programs
+that access the info struct directly incompatible with the new
+library. However, it is strongly suggested that new programs use
+the new APIs (as shown in example.c), and older programs be converted
+to the new format, to facilitate upgrades in the future.
+****
+
+Additions since 0.90 include the ability to compile libpng as a
+Windows DLL, and new APIs for accessing data in the info struct.
+Experimental functions include the ability to set weighting and cost
+factors for row filter selection, direct reads of integers from buffers
+on big-endian processors that support misaligned data access, faster
+methods of doing alpha composition, and more accurate 16->8 bit color
+conversion.
+
+The additions since 0.89 include the ability to read from a PNG stream
+which has had some (or all) of the signature bytes read by the calling
+application. This also allows the reading of embedded PNG streams that
+do not have the PNG file signature. As well, it is now possible to set
+the library action on the detection of chunk CRC errors. It is possible
+to set different actions based on whether the CRC error occurred in a
+critical or an ancillary chunk.
+
+The changes made to the library, and bugs fixed are based on discussions
+on the PNG implementation mailing list <png-implement@dworking.wustl.edu>
+and not on material submitted to Guy.
+
+For a detailed description on using libpng, read libpng.txt. For
+examples of libpng in a program, see example.c and pngtest.c. For usage
+information and restrictions (what little they are) on libpng, see
+png.h. For a description on using zlib (the compression library used by
+libpng) and zlib's restrictions, see zlib.h
+
+I have included a general makefile, as well as several machine and
+compiler specific ones, but you may have to modify one for your own needs.
+
+You should use zlib 1.0.4 or later to run this, but it MAY work with
+versions as old as zlib 0.95. Even so, there are bugs in older zlib
+versions which can cause the output of invalid compression streams for
+some images. You will definitely need zlib 1.0.4 or later if you are
+taking advantage of the MS-DOS "far" structure allocation for the small
+and medium memory models. You should also note that zlib is a
+compression library that is useful for more things than just PNG files.
+You can use zlib as a drop-in replacement for fread() and fwrite() if
+you are so inclined.
+
+zlib should be available at the same place that libpng is.
+If not, it should be at ftp.uu.net in /graphics/png
+Eventually, it will be at ftp.uu.net in /pub/archiving/zip/zlib
+
+You may also want a copy of the PNG specification. It is available
+as an RFC and a W3C Recommendation. Failing
+these resources you can try ftp.uu.net in the /graphics/png directory.
+
+This code is currently being archived at ftp.uu.net in the
+/graphics/png directory, and on CompuServe, Lib 20 (PNG SUPPORT)
+at GO GRAPHSUP. If you can't find it in any of those places,
+e-mail me, and I'll help you find it.
+
+If you have any code changes, requests, problems, etc., please e-mail
+them to me. Also, I'd appreciate any make files or project files,
+and any modifications you needed to make to get libpng to compile,
+along with a #define variable to tell what compiler/system you are on.
+If you needed to add transformations to libpng, or wish libpng would
+provide the image in a different way, drop me a note (and code, if
+possible), so I can consider supporting the transformation.
+Finally, if you get any warning messages when compiling libpng
+(note: not zlib), and they are easy to fix, I'd appreciate the
+fix. Please mention "libpng" somewhere in the subject line. Thanks.
+
+This release was created and will be supported by myself (of course
+based in a large way on Guy's and Andreas' earlier work), and the PNG group.
+
+randeg@alumni.rpi.edu
+png-implement@dworkin.wustl.edu
+
+You can't reach Guy, the original libpng author, at the addresses
+given in previous versions of this document. He and Andreas will read mail
+addressed to the png-implement list, however.
+
+Please do not send general questions about PNG. Send them to
+the address in the specification (png-group@w3.org). At the same
+time, please do not send libpng questions to that address, send them to me
+or to png-implement@dworkin.wustl.edu. I'll
+get them in the end anyway. If you have a question about something
+in the PNG specification that is related to using libpng, send it
+to me. Send me any questions that start with "I was using libpng,
+and ...". If in doubt, send questions to me. I'll bounce them
+to others, if necessary.
+
+Please do not send suggestions on how to change PNG. We have
+been discussing PNG for three years now, and it is official and
+finished. If you have suggestions for libpng, however, I'll
+gladly listen. Even if your suggestion is not used for version
+1.0, it may be used later.
+
+Files in this distribution:
+
+ CHANGES => Description of changes between libpng versions
+ README => This file
+ TODO => Things not implemented in the current library
+ ansi2knr.1 => Manual page for ansi2knr
+ ansi2knr.c => Converts files to K&R style function declarations
+ build.bat => MS-DOS batch file for Borland compiler
+ descrip.mms => VMS project file
+ example.c => Example code for using libpng functions
+ libpng.3 => manual page for libpng
+ libpng.txt => Description of libpng and its functions
+ libpngpf.3 => manual page for libpng's private functions
+ png.5 => manual page for the PNG format
+ png.c => Basic interface functions common to library
+ png.h => Library function and interface declarations
+ pngconf.h => System specific library configuration
+ pngerror.c => Error/warning message I/O functions
+ pngget.c => Functions for retrieving info from struct
+ pngmem.c => Memory handling functions
+ pngpread.c => Progressive reading functions
+ pngread.c => Read data/helper high-level functions
+ pngrio.c => Lowest-level data read I/O functions
+ pngrtran.c => Read data transformation functions
+ pngrutil.c => Read data utility functions
+ pngset.c => Functions for storing data into the info_struct
+ pngtest.c => Library test program
+ pngtest.png => Library test sample image
+ pngtrans.c => Common data transformation functions
+ pngwio.c => Lowest-level write I/O functions
+ pngwrite.c => High-level write functions
+ pngwtran.c => Write data transformations
+ pngwutil.c => Write utility functions
+ scripts => Directory containing scripts for building libpng:
+ descrip.mms => VMS makefile for MMS or MMK
+ makefile.std => Generic UNIX makefile
+ makefile.knr => Archaic UNIX Makefile that converts files with ansi2knr
+ makefile.dec => DEC Alpha UNIX makefile
+ makefile.hux => HPUX (10.20 and 11.00) makefile
+ makefile.sgi => Silicon Graphics IRIX makefile
+ makefile.sun => Sun makefile
+ makefile.s2x => Solaris 2.X makefile (gcc, creates libpng.so.2.1.0)
+ makefile.lnx => Linux/ELF makefile (gcc, creates libpng.so.2.1.0)
+ makefile.mip => MIPS makefile
+ makefile.aco => Acorn makefile
+ makefile.ama => Amiga makefile
+ smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC compiler
+ (Requires SCOPTIONS, copied from scripts/SCOPTIONS.ppc)
+ makefile.atr => Atari makefile
+ makefile.bor => Borland makefile
+ build.bat => MS-DOS batch file for Borland compiler
+ makefile.dj2 => DJGPP 2 makefile
+ makefile.msc => Microsoft C makefile
+ makefile.w32 => makefile for Microsoft Visual C++ 4.0 and later
+ makefile.tc3 => Turbo C 3.0 makefile
+ makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def)
+ makefile.wat => Watcom 10a+ Makefile, 32-bit flat memory model
+ pngos2.def => OS/2 module definition file used by makefile.os2
+ makevms.com => VMS build script
+ pngdll.mak => To make a png32bd.dll with Borland C++ 4.5
+ pngdef.pas => Defines for a png32bd.dll with Borland C++ 4.5
+
+Good luck, and happy coding.
+
+-Glenn Randers-Pehrson
+ Internet: randeg@alumni.rpi.edu
+ Web: http://www.rpi.edu/~randeg/index.html
+
+-Andreas Eric Dilger
+ Internet: adilger@enel.ucalgary.ca
+ Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/
+
+-Guy Eric Schalnat
+ (formerly of Group 42, Inc)
+ Internet: gschal@infinet.com
--- /dev/null
+foreach i (ANNOUNCE CHANGES INSTALL README TODO Y2KINFO example.c libpng.3 libpng.txt libpngpf.3 png.5 png.c png.h pngconf.h pngerror.c pngget.c pngmem.c pngpread.c pngread.c pngrio.c pngrtran.c pngrutil.c pngset.c pngtest.c pngtrans.c pngwio.c pngwrite.c pngwtran.c pngwutil.c)
+
+cvs up -rLIBPNG_1_0_3 $i
+cp $i $i.old
+cvs up -A $i
+mv $i.old $i
+cvs add $i
+
+end
--- /dev/null
+ Y2K compliance in libpng:
+ =========================
+
+ January 13, 1999
+
+ Since the PNG Development group is an ad-hoc body, we can't make
+ an official declaration.
+
+ This is your unofficial assurance that libpng from version 0.81 and
+ upward are Y2K compliant. It is my belief that earlier versions were
+ also Y2K compliant.
+
+ Libpng only has three year fields. One is a 2-byte unsigned integer
+ that will hold years up to 65535. The other two hold the date in text
+ format, and will hold years up to 9999.
+
+ The integer is
+ "png_uint_16 year" in png_time_struct.
+
+ The strings are
+ "png_charp time_buffer" in png_struct and
+ "near_time_buffer", which is a local character string in png.c.
+
+ There are seven time-related functions:
+
+ png_convert_to_rfc_1123() in png.c
+ (formerly png_convert_to_rfc_1152() in error)
+ png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ png_convert_from_time_t() in pngwrite.c
+ png_get_tIME() in pngget.c
+ png_handle_tIME() in pngrutil.c, called in pngread.c
+ png_set_tIME() in pngset.c
+ png_write_tIME() in pngwutil.c, called in pngwrite.c
+
+ All appear to handle dates properly in a Y2K environment. The
+ png_convert_from_time_t() function calls gmtime() to convert from system
+ clock time, which returns (year - 1900), which we properly convert to
+ the full 4-digit year. There is a possibility that applications using
+ libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+ function, or incorrectly passing only a 2-digit year instead of
+ "year - 1900" into the png_convert_from_struct_tm() function, but this
+ is not under our control. The libpng documentation has always stated
+ that it works with 4-digit years, and the APIs have been documented as
+ such.
+
+ The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+ integer to hold the year, and can hold years as large as 65535.
+
+
+ Glenn Randers-Pehrson
+ libpng maintainer
+ PNG Development Group
--- /dev/null
+
+/* example.c - an example of using libpng */
+
+/* This is an example of how to use libpng to read and write PNG files.
+ * The file libpng.txt is much more verbose then this. If you have not
+ * read it, do so first. This was designed to be a starting point of an
+ * implementation. This is not officially part of libpng, and therefore
+ * does not require a copyright notice.
+ *
+ * This file does not currently compile, because it is missing certain
+ * parts, like allocating memory to hold an image. You will have to
+ * supply these parts to get it to compile. For an example of a minimal
+ * working PNG reader/writer, see pngtest.c, included in this distribution.
+ */
+
+#include "png.h"
+
+/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp()
+ * returns zero if the image is a PNG and nonzero if it isn't a PNG.
+ *
+ * The function check_if_png() shown here, but not used, returns nonzero (true)
+ * if the file can be opened and is a PNG, 0 (false) otherwise.
+ *
+ * If this call is successful, and you are going to keep the file open,
+ * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
+ * you have created the png_ptr, so that libpng knows your application
+ * has read that many bytes from the start of the file. Make sure you
+ * don't call png_set_sig_bytes() with more than 8 bytes read or give it
+ * an incorrect number of bytes read, or you will either have read too
+ * many bytes (your fault), or you are telling libpng to read the wrong
+ * number of magic bytes (also your fault).
+ *
+ * Many applications already read the first 2 or 4 bytes from the start
+ * of the image to determine the file type, so it would be easiest just
+ * to pass the bytes to png_sig_cmp() or even skip that if you know
+ * you have a PNG file, and call png_set_sig_bytes().
+ */
+#define PNG_BYTES_TO_CHECK 4
+int check_if_png(char *file_name, FILE **fp)
+{
+ char buf[PNG_BYTES_TO_CHECK];
+
+ /* Open the prospective PNG file. */
+ if ((*fp = fopen(file_name, "rb")) != NULL);
+ return 0;
+
+ /* Read in some of the signature bytes */
+ if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
+ return 0;
+
+ /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
+ Return nonzero (true) if they match */
+
+ return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
+}
+
+/* Read a PNG file. You may want to return an error code if the read
+ * fails (depending upon the failure). There are two "prototypes" given
+ * here - one where we are given the filename, and we need to open the
+ * file, and the other where we are given an open file (possibly with
+ * some or all of the magic bytes read - see comments above).
+ */
+#ifdef open_file /* prototype 1 */
+void read_png(char *file_name) /* We need to open the file */
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned int sig_read = 0;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+ FILE *fp;
+
+ if ((fp = fopen(file_name, "rb")) == NULL)
+ return;
+#else no_open_file /* prototype 2 */
+void read_png(FILE *fp, unsigned int sig_read) /* file is already open */
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+#endif no_open_file /* only use one prototype! */
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also supply the
+ * the compiler header file version, so that we know if the application
+ * was compiled with a compatible version of the library. REQUIRED
+ */
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ png_voidp user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ return;
+ }
+
+ /* Allocate/initialize the memory for image information. REQUIRED. */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return;
+ }
+
+ /* Set error handling if you are using the setjmp/longjmp method (this is
+ * the normal method of doing things with libpng). REQUIRED unless you
+ * set up your own error handlers in the png_create_read_struct() earlier.
+ */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ /* Free all of the memory associated with the png_ptr and info_ptr */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ fclose(fp);
+ /* If we get here, we had a problem reading the file */
+ return;
+ }
+
+ /* One of the following I/O initialization methods is REQUIRED */
+#ifdef streams /* PNG file I/O method 1 */
+ /* Set up the input control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+
+#else no_streams /* PNG file I/O method 2 */
+ /* If you are using replacement read functions, instead of calling
+ * png_init_io() here you would call:
+ */
+ png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
+ /* where user_io_ptr is a structure you want available to the callbacks */
+#endif no_streams /* Use only one I/O method! */
+
+ /* If we have already read some of the signature */
+ png_set_sig_bytes(png_ptr, sig_read);
+
+ /* The call to png_read_info() gives us all of the information from the
+ * PNG file before the first IDAT (image data chunk). REQUIRED
+ */
+ png_read_info(png_ptr, info_ptr);
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+
+/**** Set up the data transformations you want. Note that these are all
+ **** optional. Only call them if you want/need them. Many of the
+ **** transformations only work on specific types of images, and many
+ **** are mutually exclusive.
+ ****/
+
+ /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+ png_set_strip_16(png_ptr);
+
+ /* Strip alpha bytes from the input data without combining with th
+ * background (not recommended).
+ */
+ png_set_strip_alpha(png_ptr);
+
+ /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
+ * byte into separate bytes (useful for paletted and grayscale images).
+ */
+ png_set_packing(png_ptr);
+
+ /* Change the order of packed pixels to least significant bit first
+ * (not useful if you are using png_set_packing). */
+ png_set_packswap(png_ptr);
+
+ /* Expand paletted colors into true RGB triplets */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+
+ /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ /* Expand paletted or RGB images with transparency to full alpha channels
+ * so the data will be available as RGBA quartets.
+ */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+
+ /* Set the background color to draw transparent and alpha images over.
+ * It is possible to set the red, green, and blue components directly
+ * for paletted images instead of supplying a palette index. Note that
+ * even if the PNG file supplies a background, you are not required to
+ * use it - you should use the (solid) application background if it has one.
+ */
+
+ png_color_16 my_background, *image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+ /* Some suggestions as to how to get a screen gamma value */
+
+ /* Note that screen gamma is (display_gamma/viewing_gamma) */
+ if (/* We have a user-defined screen gamma value */)
+ {
+ screen_gamma = user-defined screen_gamma;
+ }
+ /* This is one way that applications share the same screen gamma value */
+ else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
+ {
+ screen_gamma = atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly
+ lit room */
+ screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */
+ }
+
+ /* Tell libpng to handle the gamma conversion for you. The second call
+ * is a good guess for PC generated images, but it should be configurable
+ * by the user at run time by the user. It is strongly suggested that
+ * your application support gamma correction.
+ */
+
+ int intent;
+
+ if (png_get_sRGB(png_ptr, info_ptr, &intent))
+ png_set_sRGB(png_ptr, intent, 0);
+ else
+ {
+ double image_gamma;
+ if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
+ png_set_gamma(png_ptr, screen_gamma, image_gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+ }
+
+ /* Dither RGB files down to 8 bit palette or reduce palettes
+ * to the number of colors available on your screen.
+ */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_uint_32 num_palette;
+ png_colorp palette;
+
+ /* This reduces the image to the application supplied palette */
+ if (/* we have our own palette */)
+ {
+ /* An array of colors to which the image should be dithered */
+ png_color std_color_cube[MAX_SCREEN_COLORS];
+
+ png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
+ MAX_SCREEN_COLORS, NULL, 0);
+ }
+ /* This reduces the image to the palette supplied in the file */
+ else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
+ {
+ png_color16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr, &histogram);
+
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 0);
+ }
+ }
+
+ /* invert monocrome files to have 0 as white and 1 as black */
+ png_set_invert_mono(png_ptr);
+
+ /* If you want to shift the pixel values from the range [0,255] or
+ * [0,65535] to the original [0,7] or [0,31], or whatever range the
+ * colors were originally in:
+ */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
+ {
+ png_color8p sig_bit;
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ png_set_shift(png_ptr, sig_bit);
+ }
+
+ /* flip the RGB pixels to BGR (or RGBA to BGRA) */
+ png_set_bgr(png_ptr);
+
+ /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+ png_set_swap_alpha(png_ptr);
+
+ /* swap bytes of 16 bit files to least significant byte first */
+ png_set_swap(png_ptr);
+
+ /* Add filler (or alpha) byte (before/after each RGB triplet) */
+ png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+ /* Turn on interlace handling. REQUIRED if you are not using
+ * png_read_image(). To see how to handle interlacing passes,
+ * see the png_read_row() method below:
+ */
+ number_passes = png_set_interlace_handling(png_ptr);
+
+ /* Optional call to gamma correct and add the background to the palette
+ * and update info structure. REQUIRED if you are expecting libpng to
+ * update the palette for you (ie you selected such a transform above).
+ */
+ png_read_update_info(png_ptr, info_ptr);
+
+ /* Allocate the memory to hold the image using the fields of info_ptr. */
+
+ /* The easiest way to read the image: */
+ png_bytep row_pointers[height];
+
+ for (row = 0; row < height; row++)
+ {
+ row_pointers[row] = malloc(png_get_rowbytes(png_ptr, info_ptr));
+ }
+
+ /* Now it's time to read the image. One of these methods is REQUIRED */
+#ifdef entire /* Read the entire image in one go */
+ png_read_image(png_ptr, row_pointers);
+
+#else no_entire /* Read the image one or more scanlines at a time */
+ /* The other way to read images - deal with interlacing: */
+
+ for (pass = 0; pass < number_passes; pass++)
+ {
+#ifdef single /* Read the image a single row at a time */
+ for (y = 0; y < height; y++)
+ {
+ png_read_rows(png_ptr, &row_pointers[y], NULL, 1);
+ }
+
+#else no_single /* Read the image several rows at a time */
+ for (y = 0; y < height; y += number_of_rows)
+ {
+#ifdef sparkle /* Read the image using the "sparkle" effect. */
+ png_read_rows(png_ptr, &row_pointers[y], NULL, number_of_rows);
+
+ png_read_rows(png_ptr, NULL, row_pointers[y], number_of_rows);
+#else no_sparkle /* Read the image using the "rectangle" effect */
+ png_read_rows(png_ptr, NULL, &row_pointers[y], number_of_rows);
+#endif no_sparkle /* use only one of these two methods */
+ }
+
+ /* if you want to display the image after every pass, do
+ so here */
+#endif no_single /* use only one of these two methods */
+ }
+#endif no_entire /* use only one of these two methods */
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end(png_ptr, info_ptr);
+
+ /* clean up after the read, and free any memory allocated - REQUIRED */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return;
+}
+
+/* progressively read a file */
+
+int
+initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
+{
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible in case we are using dynamically
+ * linked libraries.
+ */
+ *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ png_voidp user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (*png_ptr == NULL)
+ {
+ *info_ptr = NULL;
+ return ERROR;
+ }
+
+ *info_ptr = png_create_info_struct(png_ptr);
+
+ if (*info_ptr == NULL)
+ {
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return ERROR;
+ }
+
+ if (setjmp((*png_ptr)->jmpbuf))
+ {
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return ERROR;
+ }
+
+ /* This one's new. You will need to provide all three
+ * function callbacks, even if you aren't using them all.
+ * If you aren't using all functions, you can specify NULL
+ * parameters. Even when all three functions are NULL,
+ * you need to call png_set_progressive_read_fn().
+ * These functions shouldn't be dependent on global or
+ * static variables if you are decoding several images
+ * simultaneously. You should store stream specific data
+ * in a separate struct, given as the second parameter,
+ * and retrieve the pointer from inside the callbacks using
+ * the function png_get_progressive_ptr(png_ptr).
+ */
+ png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
+ info_callback, row_callback, end_callback);
+
+ return OK;
+}
+
+int
+process_data(png_structp *png_ptr, png_infop *info_ptr,
+ png_bytep buffer, png_uint_32 length)
+{
+ if (setjmp((*png_ptr)->jmpbuf))
+ {
+ /* Free the png_ptr and info_ptr memory on error */
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return ERROR;
+ }
+
+ /* This one's new also. Simply give it chunks of data as
+ * they arrive from the data stream (in order, of course).
+ * On Segmented machines, don't give it any more than 64K.
+ * The library seems to run fine with sizes of 4K, although
+ * you can give it much less if necessary (I assume you can
+ * give it chunks of 1 byte, but I haven't tried with less
+ * than 256 bytes yet). When this function returns, you may
+ * want to display any rows that were generated in the row
+ * callback, if you aren't already displaying them there.
+ */
+ png_process_data(*png_ptr, *info_ptr, buffer, length);
+ return OK;
+}
+
+info_callback(png_structp png_ptr, png_infop info)
+{
+/* do any setup here, including setting any of the transformations
+ * mentioned in the Reading PNG files section. For now, you _must_
+ * call either png_start_read_image() or png_read_update_info()
+ * after all the transformations are set (even if you don't set
+ * any). You may start getting rows before png_process_data()
+ * returns, so this is your last chance to prepare for that.
+ */
+}
+
+row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+{
+/* this function is called for every row in the image. If the
+ * image is interlacing, and you turned on the interlace handler,
+ * this function will be called for every row in every pass.
+ * Some of these rows will not be changed from the previous pass.
+ * When the row is not changed, the new_row variable will be NULL.
+ * The rows and passes are called in order, so you don't really
+ * need the row_num and pass, but I'm supplying them because it
+ * may make your life easier.
+ *
+ * For the non-NULL rows of interlaced images, you must call
+ * png_progressive_combine_row() passing in the row and the
+ * old row. You can call this function for NULL rows (it will
+ * just return) and for non-interlaced images (it just does the
+ * memcpy for you) if it will make the code easier. Thus, you
+ * can just do this for all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row, new_row);
+
+/* where old_row is what was displayed for previous rows. Note
+ * that the first pass (pass == 0 really) will completely cover
+ * the old row, so the rows do not have to be initialized. After
+ * the first pass (and only for interlaced images), you will have
+ * to pass the current row, and the function will combine the
+ * old row and the new row.
+ */
+}
+
+end_callback(png_structp png_ptr, png_infop info)
+{
+/* this function is called when the whole image has been read,
+ * including any chunks after the image (up to and including
+ * the IEND). You will usually have the same info chunk as you
+ * had in the header, although some data may have been added
+ * to the comments and time fields.
+ *
+ * Most people won't do much here, perhaps setting a flag that
+ * marks the image as finished.
+ */
+}
+
+/* write a png file */
+void write_png(char *file_name /* , ... other image information ... */)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ /* open the file */
+ fp = fopen(file_name, "wb");
+ if (fp == NULL)
+ return;
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible with the one used at compile time,
+ * in case we are using dynamically linked libraries. REQUIRED.
+ */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ png_voidp user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ return;
+ }
+
+ /* Allocate/initialize the image information data. REQUIRED */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return;
+ }
+
+ /* Set error handling. REQUIRED if you aren't supplying your own
+ * error hadnling functions in the png_create_write_struct() call.
+ */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ /* If we get here, we had a problem reading the file */
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return;
+ }
+
+ /* One of the following I/O initialization functions is REQUIRED */
+#ifdef streams /* I/O initialization method 1 */
+ /* set up the output control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+#else no_streams /* I/O initialization method 2 */
+ /* If you are using replacement read functions, instead of calling
+ * png_init_io() here you would call */
+ png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn,
+ user_IO_flush_function);
+ /* where user_io_ptr is a structure you want available to the callbacks */
+#endif no_streams /* only use one initialization method */
+
+ /* Set the image information here. Width and height are up to 2^31,
+ * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
+ * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
+ * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
+ * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
+ * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
+ * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
+ */
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???,
+ PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ /* set the palette if there is one. REQUIRED for indexed-color images */
+ palette = (png_colorp)png_malloc(png_ptr, 256 * sizeof (png_color));
+ /* ... set palette colors ... */
+ png_set_PLTE(png_ptr, info_ptr, palette, 256);
+
+ /* optional significant bit chunk */
+ /* if we are dealing with a grayscale image then */
+ sig_bit.gray = true_bit_depth;
+ /* otherwise, if we are dealing with a color image then */
+ sig_bit.red = true_red_bit_depth;
+ sig_bit.green = true_green_bit_depth;
+ sig_bit.blue = true_blue_bit_depth;
+ /* if the image has an alpha channel then */
+ sig_bit.alpha = true_alpha_bit_depth;
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+
+
+ /* Optional gamma chunk is strongly suggested if you have any guess
+ * as to the correct gamma of the image.
+ */
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+
+ /* Optionally write comments into the image */
+ text_ptr[0].key = "Title";
+ text_ptr[0].text = "Mona Lisa";
+ text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[1].key = "Author";
+ text_ptr[1].text = "Leonardo DaVinci";
+ text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[2].key = "Description";
+ text_ptr[2].text = "<long text>";
+ text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
+ png_set_text(png_ptr, info_ptr, text_ptr, 3);
+
+ /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
+ /* note that if sRGB is present the cHRM chunk must be ignored
+ * on read and must be written in accordance with the sRGB profile */
+
+ /* Write the file header information. REQUIRED */
+ png_write_info(png_ptr, info_ptr);
+
+ /* Once we write out the header, the compression type on the text
+ * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+ * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
+ * at the end.
+ */
+
+ /* set up the transformations you want. Note that these are
+ * all optional. Only call them if you want them.
+ */
+
+ /* invert monocrome pixels */
+ png_set_invert_mono(png_ptr);
+
+ /* Shift the pixels up to a legal bit depth and fill in
+ * as appropriate to correctly scale the image.
+ */
+ png_set_shift(png_ptr, &sig_bit);
+
+ /* pack pixels into bytes */
+ png_set_packing(png_ptr);
+
+ /* swap location of alpha bytes from ARGB to RGBA */
+ png_set_swap_alpha(png_ptr);
+
+ /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
+ * RGB (4 channels -> 3 channels). The second parameter is not used.
+ */
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+ /* flip BGR pixels to RGB */
+ png_set_bgr(png_ptr);
+
+ /* swap bytes of 16-bit files to most significant byte first */
+ png_set_swap(png_ptr);
+
+ /* swap bits of 1, 2, 4 bit packed pixel formats */
+ png_set_packswap(png_ptr);
+
+ /* turn on interlace handling if you are not using png_write_image() */
+ if (interlacing)
+ number_passes = png_set_interlace_handling(png_ptr);
+ else
+ number_passes = 1;
+
+ /* The easiest way to write the image (you may have a different memory
+ * layout, however, so choose what fits your needs best). You need to
+ * use the first method if you aren't handling interlacing yourself.
+ */
+ png_uint_32 k, height, width;
+ png_byte image[height][width];
+ png_bytep row_pointers[height];
+ for (k = 0; k < height; k++)
+ row_pointers[k] = image + k*width;
+
+ /* One of the following output methods is REQUIRED */
+#ifdef entire /* write out the entire image data in one call */
+ png_write_image(png_ptr, row_pointers);
+
+ /* the other way to write the image - deal with interlacing */
+
+#else no_entire /* write out the image data by one or more scanlines */
+ /* The number of passes is either 1 for non-interlaced images,
+ * or 7 for interlaced images.
+ */
+ for (pass = 0; pass < number_passes; pass++)
+ {
+ /* Write a few rows at a time. */
+ png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows);
+
+ /* If you are only writing one row at a time, this works */
+ for (y = 0; y < height; y++)
+ {
+ png_write_rows(png_ptr, &row_pointers[y], 1);
+ }
+ }
+#endif no_entire /* use only one output method */
+
+ /* You can write optional chunks like tEXt, zTXt, and tIME at the end
+ * as well.
+ */
+
+ /* It is REQUIRED to call this to finish writing the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+
+ /* if you malloced the palette, free it here */
+ free(info_ptr->palette);
+
+ /* if you allocated any text comments, free them here */
+
+ /* clean up after the write, and free any memory allocated */
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return;
+}
+
--- /dev/null
+.TH LIBPNG 3 "January 14, 1999"
+.SH NAME
+libpng \- Portable Network Graphics (PNG) Reference Library 1.0.3 - January 14, 1999
+.SH SYNOPSIS
+
+#include <png.h>
+
+int png_check_sig (png_bytep sig, int num);
+
+void png_chunk_error (png_structp png_ptr, png_const_charp
+error);
+
+void png_chunk_warning (png_structp png_ptr, png_const_charp
+message);
+
+void png_convert_from_struct_tm (png_timep ptime, struct tm FAR
+* ttime);
+
+void png_convert_from_time_t (png_timep ptime, time_t ttime);
+
+png_charp png_convert_to_rfc1123 (png_structp png_ptr,
+png_timep ptime);
+
+png_infop png_create_info_struct (png_structp png_ptr);
+
+png_structp png_create_read_struct (png_const_charp
+user_png_ver, voidp error_ptr, png_error_ptr error_fn,
+png_error_ptr warn_fn);
+
+png_structp png_create_read_struct_2(png_const_charp user_png_ver,
+png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr
+warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn,
+png_free_ptr free_fn)
+
+png_structp png_create_write_struct (png_const_charp
+user_png_ver, voidp error_ptr, png_error_ptr error_fn,
+png_error_ptr warn_fn);
+
+png_structp png_create_write_struct_2(png_const_charp
+user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
+png_error_ptr warn_fn, png_voidp mem_ptr,
+png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+
+int png_debug(int level, png_const_charp message)
+
+int png_debug1(int level, png_const_charp message, p1)
+
+int png_debug2(int level, png_const_charp message, p1, p2)
+
+void png_destroy_info_struct (png_structp png_ptr, png_infopp
+info_ptr_ptr);
+
+void png_destroy_read_struct (png_structpp png_ptr_ptr,
+png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr);
+
+void png_destroy_write_struct (png_structpp png_ptr_ptr,
+png_infopp info_ptr_ptr);
+
+void png_error (png_structp png_ptr, png_const_charp error);
+
+void png_free (png_structp png_ptr, png_voidp ptr);
+
+void png_free_default(png_structp png_ptr, png_voidp ptr)
+
+png_byte png_get_bit_depth (png_structp png_ptr, png_infop
+info_ptr);
+
+png_uint_32 png_get_bKGD (png_structp png_ptr, png_infop
+info_ptr, png_color_16p *background);
+
+png_byte png_get_channels (png_structp png_ptr, png_infop
+info_ptr);
+
+png_uint_32 png_get_cHRM (png_structp png_ptr, png_infop
+info_ptr, double *white_x, double *white_y, double *red_x,
+double *red_y, double *green_x, double *green_y, double
+*blue_x, double *blue_y);
+
+png_byte png_get_color_type (png_structp png_ptr, png_infop
+info_ptr);
+
+png_byte png_get_compression_type (png_structp png_ptr,
+png_infop info_ptr);
+
+png_byte png_get_copyright (png_structp png_ptr);
+
+png_voidp png_get_error_ptr (png_structp png_ptr);
+
+png_byte png_get_filter_type (png_structp png_ptr, png_infop
+info_ptr);
+
+png_uint_32 png_get_gAMA (png_structp png_ptr, png_infop
+info_ptr, double *file_gamma);
+
+png_byte png_get_header_version (png_structp png_ptr);
+
+png_uint_32 png_get_hIST (png_structp png_ptr, png_infop
+info_ptr, png_uint_16p *hist);
+
+png_uint_32 png_get_IHDR (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 *width, png_uint_32 *height, int
+*bit_depth, int *color_type, int *interlace_type, int
+*compression_type, int *filter_type);
+
+png_uint_32 png_get_image_height (png_structp png_ptr,
+png_infop info_ptr);
+
+png_uint_32 png_get_image_width (png_structp png_ptr, png_infop
+info_ptr);
+
+png_byte png_get_interlace_type (png_structp png_ptr, png_infop
+info_ptr);
+
+png_voidp png_get_io_ptr (png_structp png_ptr);
+
+png_voidp png_get_mem_ptr(png_structp png_ptr)
+
+png_uint_32 png_get_oFFs (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 *offset_x, png_uint_32 *offset_y, int
+*unit_type);
+
+png_uint_32 png_get_pCAL (png_structp png_ptr, png_infop
+info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
+int *type, int *nparams, png_charp *units, png_charpp *params);
+
+png_uint_32 png_get_pHYs (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int
+*unit_type);
+
+float png_get_pixel_aspect_ratio (png_structp png_ptr,
+png_infop info_ptr);
+
+png_uint_32 png_get_pixels_per_meter (png_structp png_ptr,
+png_infop info_ptr);
+
+png_voidp png_get_progressive_ptr (png_structp png_ptr);
+
+png_uint_32 png_get_PLTE (png_structp png_ptr, png_infop
+info_ptr, png_colorp *palette, int *num_palette);
+
+png_byte png_get_rgb_to_gray_status (png_structp png_ptr)
+
+png_uint_32 png_get_rowbytes (png_structp png_ptr, png_infop
+info_ptr);
+
+png_uint_32 png_get_sBIT (png_structp png_ptr, png_infop
+info_ptr, png_color_8p *sig_bit);
+
+png_bytep png_get_signature (png_structp png_ptr, png_infop
+info_ptr);
+
+png_uint_32 png_get_sRGB (png_structp png_ptr, png_infop
+info_ptr, int *intent);
+
+png_uint_32 png_get_text (png_structp png_ptr, png_infop
+info_ptr, png_textp *text_ptr, int *num_text);
+
+png_uint_32 png_get_tIME (png_structp png_ptr, png_infop
+info_ptr, png_timep *mod_time);
+
+png_uint_32 png_get_tRNS (png_structp png_ptr, png_infop
+info_ptr, png_bytep *trans, int *num_trans, png_color_16p
+*trans_values);
+
+png_uint_32 png_get_valid (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 flag);
+
+png_uint_32 png_get_x_offset_microns (png_structp png_ptr,
+png_infop info_ptr);
+
+png_uint_32 png_get_x_offset_pixels (png_structp png_ptr,
+png_infop info_ptr);
+
+png_uint_32 png_get_x_pixels_per_meter (png_structp png_ptr,
+png_infop info_ptr);
+
+png_uint_32 png_get_y_offset_microns (png_structp png_ptr,
+png_infop info_ptr);
+
+png_uint_32 png_get_y_offset_pixels (png_structp png_ptr,
+png_infop info_ptr);
+
+png_uint_32 png_get_y_pixels_per_meter (png_structp png_ptr,
+png_infop info_ptr);
+
+void png_info_init (png_infop info_ptr);
+
+void png_init_io (png_structp png_ptr, FILE *fp);
+
+png_voidp png_malloc (png_structp png_ptr, png_uint_32 size);
+
+png_voidp png_malloc_default(png_structp png_ptr,
+png_uint_32 size)
+
+voidp png_memcpy (png_voidp s1, png_voidp s2, png_size_t size);
+
+png_voidp png_memcpy_check (png_structp png_ptr, png_voidp s1,
+png_voidp s2, png_uint_32 size);
+
+voidp png_memset (png_voidp s1, int value, png_size_t size);
+
+png_voidp png_memset_check (png_structp png_ptr, png_voidp
+s1, int value, png_uint_32 size);
+
+void png_process_data (png_structp png_ptr, png_infop info_ptr,
+png_bytep buffer, png_size_t buffer_size);
+
+void png_progressive_combine_row (png_structp png_ptr,
+png_bytep old_row, png_bytep new_row);
+
+void png_read_destroy (png_structp png_ptr, png_infop info_ptr,
+png_infop end_info_ptr);
+
+void png_read_end (png_structp png_ptr, png_infop info_ptr);
+
+void png_read_image (png_structp png_ptr, png_bytepp image);
+
+void png_read_info (png_structp png_ptr, png_infop info_ptr);
+
+void png_read_row (png_structp png_ptr, png_bytep row,
+png_bytep display_row);
+
+void png_read_rows (png_structp png_ptr, png_bytepp row,
+png_bytepp display_row, png_uint_32 num_rows);
+
+void png_read_update_info (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_set_background (png_structp png_ptr, png_color_16p
+background_color, int background_gamma_code, int need_expand,
+double background_gamma);
+
+void png_set_bgr (png_structp png_ptr);
+
+void png_set_bKGD (png_structp png_ptr, png_infop info_ptr,
+png_color_16p background);
+
+void png_set_cHRM (png_structp png_ptr, png_infop info_ptr,
+double white_x, double white_y, double red_x, double red_y,
+double green_x, double green_y, double blue_x, double blue_y);
+
+void png_set_compression_level (png_structp png_ptr, int
+level);
+
+void png_set_compression_mem_level (png_structp png_ptr, int
+mem_level);
+
+void png_set_compression_method (png_structp png_ptr, int
+method);
+
+void png_set_compression_strategy (png_structp png_ptr, int
+strategy);
+
+void png_set_compression_window_bits (png_structp png_ptr, int
+window_bits);
+
+void png_set_crc_action (png_structp png_ptr, int crit_action,
+int ancil_action);
+
+void png_set_dither (png_structp png_ptr, png_colorp palette,
+int num_palette, int maximum_colors, png_uint_16p histogram,
+int full_dither);
+
+void png_set_error_fn (png_structp png_ptr, png_voidp
+error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn);
+
+void png_set_expand (png_structp png_ptr);
+
+void png_set_filler (png_structp png_ptr, png_uint_32 filler,
+int flags);
+
+void png_set_filter (png_structp png_ptr, int method, int
+filters);
+
+void png_set_filter_heuristics (png_structp png_ptr, int
+heuristic_method, int num_weights, png_doublep filter_weights,
+png_doublep filter_costs);
+
+void png_set_flush (png_structp png_ptr, int nrows);
+
+void png_set_gamma (png_structp png_ptr, double screen_gamma,
+double default_file_gamma);
+
+void png_set_gAMA (png_structp png_ptr, png_infop info_ptr,
+double file_gamma);
+
+void png_set_gray_to_rgb (png_structp png_ptr);
+
+void png_set_hIST (png_structp png_ptr, png_infop info_ptr,
+png_uint_16p hist);
+
+int png_set_interlace_handling (png_structp png_ptr);
+
+void png_set_invert_alpha (png_structp png_ptr);
+
+void png_set_invert_mono (png_structp png_ptr);
+
+void png_set_IHDR (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 width, png_uint_32 height, int bit_depth, int
+color_type, int interlace_type, int compression_type, int
+filter_type);
+
+void png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr,
+png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+
+void png_set_oFFs (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 offset_x, png_uint_32 offset_y, int unit_type);
+
+void png_set_packing (png_structp png_ptr);
+
+void png_set_packswap (png_structp png_ptr);
+
+void png_set_pCAL (png_structp png_ptr, png_infop info_ptr,
+png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int
+nparams, png_charp units, png_charpp params);
+
+void png_set_pHYs (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 res_x, png_uint_32 res_y, int unit_type);
+
+void png_set_progressive_read_fn (png_structp png_ptr,
+png_voidp progressive_ptr, png_progressive_info_ptr info_fn,
+png_progressive_row_ptr row_fn, png_progressive_end_ptr
+end_fn);
+
+void png_set_PLTE (png_structp png_ptr, png_infop info_ptr,
+png_colorp palette, int num_palette);
+
+void png_set_read_fn (png_structp png_ptr, png_voidp io_ptr,
+png_rw_ptr read_data_fn);
+
+void png_set_read_status_fn (png_structp png_ptr, png_read_status_ptr
+read_row_fn);
+
+void png_set_read_user_transform_fn (png_structp png_ptr,
+png_user_transform_ptr read_user_transform_fn);
+
+void png_set_rgb_to_gray (png_structp png_ptr, int error_action);
+
+void png_set_sBIT (png_structp png_ptr, png_infop info_ptr,
+png_color_8p sig_bit);
+
+void png_set_shift (png_structp png_ptr, png_color_8p
+true_bits);
+
+void png_set_sig_bytes (png_structp png_ptr, int num_bytes);
+
+void png_set_sRGB (png_structp png_ptr, png_infop info_ptr, int
+intent);
+
+void png_set_sRGB_gAMA_and_cHRM (png_structp png_ptr, png_infop
+info_ptr, int intent);
+
+void png_set_strip_16 (png_structp png_ptr);
+
+void png_set_strip_alpha (png_structp png_ptr);
+
+void png_set_swap (png_structp png_ptr);
+
+void png_set_swap_alpha (png_structp png_ptr);
+
+void png_set_text (png_structp png_ptr, png_infop info_ptr,
+png_textp text_ptr, int num_text);
+
+void png_set_tIME (png_structp png_ptr, png_infop info_ptr,
+png_timep mod_time);
+
+void png_set_tRNS (png_structp png_ptr, png_infop info_ptr,
+png_bytep trans, int num_trans, png_color_16p trans_values);
+
+void png_set_write_fn (png_structp png_ptr, png_voidp io_ptr,
+png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn);
+
+void png_set_write_status_fn (png_structp png_ptr, png_write_status_ptr
+write_row_fn);
+
+void png_set_write_user_transform_fn (png_structp png_ptr,
+png_user_transform_ptr write_user_transform_fn);
+
+int png_sig_cmp (png_bytep sig, png_size_t start, png_size_t
+num_to_check);
+
+void png_start_read_image (png_structp png_ptr);
+
+void png_warning (png_structp png_ptr, png_const_charp
+message);
+
+void png_write_chunk (png_structp png_ptr, png_bytep
+chunk_name, png_bytep data, png_size_t length);
+
+void png_write_chunk_data (png_structp png_ptr, png_bytep data,
+png_size_t length);
+
+void png_write_chunk_end (png_structp png_ptr);
+
+void png_write_chunk_start (png_structp png_ptr, png_bytep
+chunk_name, png_uint_32 length);
+
+void png_write_destroy (png_structp png_ptr);
+
+void png_write_destroy_info (png_infop info_ptr);
+
+void png_write_end (png_structp png_ptr, png_infop info_ptr);
+
+void png_write_flush (png_structp png_ptr);
+
+void png_write_image (png_structp png_ptr, png_bytepp image);
+
+void png_write_info (png_structp png_ptr, png_infop info_ptr);
+
+void png_write_row (png_structp png_ptr, png_bytep row);
+
+void png_write_rows (png_structp png_ptr, png_bytepp row,
+png_uint_32 num_rows);
+
+.SH DESCRIPTION
+The
+.I libpng
+library supports encoding, decoding, and various manipulations of
+the Portable Network Graphics (PNG) format image files. It uses the
+.IR zlib(3)
+compression library.
+Following is a copy of the libpng.txt file that accompanies libpng.
+.SH LIBPNG.TXT
+libpng.txt - A description on how to use and modify libpng
+
+ libpng version 1.0.3 - January 14, 1999
+ Updated and distributed by Glenn Randers-Pehrson
+ <randeg@alumni.rpi.edu>
+ Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ For conditions of distribution and use, see copyright
+ notice in png.h.
+
+ based on:
+
+ libpng 1.0 beta 6 version 0.96 May 28, 1997
+ Updated and distributed by Andreas Dilger
+ Copyright (c) 1996, 1997 Andreas Dilger
+
+ libpng 1.0 beta 2 - version 0.88 January 26, 1996
+ For conditions of distribution and use, see copyright
+ notice in png.h. Copyright (c) 1995, 1996 Guy Eric
+ Schalnat, Group 42, Inc.
+
+ Updated/rewritten per request in the libpng FAQ
+ Copyright (c) 1995 Frank J. T. Wojcik
+ December 18, 1995 && January 20, 1996
+
+.SH I. Introduction
+
+This file describes how to use and modify the PNG reference library
+(known as libpng) for your own use. There are five sections to this
+file: introduction, structures, reading, writing, and modification and
+configuration notes for various special platforms. In addition to this
+file, example.c is a good starting point for using the library, as
+it is heavily commented and should include everything most people
+will need. We assume that libpng is already installed; see the
+INSTALL file for instructions on how to install libpng.
+
+Libpng was written as a companion to the PNG specification, as a way
+of reducing the amount of time and effort it takes to support the PNG
+file format in application programs. The PNG specification is available
+as RFC 2083 <ftp://ftp.uu.net/graphics/png/documents/> and as a
+W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some
+additional chunks are described in the special-purpose public chunks
+documents at <ftp://ftp.uu.net/graphics/png/documents/>. Other information
+about PNG, and the latest version of libpng, can be found at the PNG home
+page, <http://www.cdrom.com/pub/png/>.
+
+Most users will not have to modify the library significantly; advanced
+users may want to modify it more. All attempts were made to make it as
+complete as possible, while keeping the code easy to understand.
+Currently, this library only supports C. Support for other languages
+is being considered.
+
+Libpng has been designed to handle multiple sessions at one time,
+to be easily modifiable, to be portable to the vast majority of
+machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
+to use. The ultimate goal of libpng is to promote the acceptance of
+the PNG file format in whatever way possible. While there is still
+work to be done (see the TODO file), libpng should cover the
+majority of the needs of its users.
+
+Libpng uses zlib for its compression and decompression of PNG files.
+Further information about zlib, and the latest version of zlib, can
+be found at the zlib home page, <http://www.cdrom.com/pub/infozip/zlib/>.
+The zlib compression utility is a general purpose utility that is
+useful for more than PNG files, and can be used without libpng.
+See the documentation delivered with zlib for more details.
+You can usually find the source files for the zlib utility wherever you
+find the libpng source files.
+
+Libpng is thread safe, provided the threads are using different
+instances of the structures. Each thread should have its own
+png_struct and png_info instances, and thus its own image.
+Libpng does not protect itself against two threads using the
+same instance of a structure.
+
+
+.SH II. Structures
+
+There are two main structures that are important to libpng, png_struct
+and png_info. The first, png_struct, is an internal structure that
+will not, for the most part, be used by a user except as the first
+variable passed to every libpng function call.
+
+The png_info structure is designed to provide information about the
+PNG file. At one time, the fields of png_info were intended to be
+directly accessible to the user. However, this tended to cause problems
+with applications using dynamically loaded libraries, and as a result
+a set of interface functions for png_info was developed. The fields
+of png_info are still available for older applications, but it is
+suggested that applications use the new interfaces if at all possible.
+
+The png.h header file is an invaluable reference for programming with libpng.
+And while I'm on the topic, make sure you include the libpng header file:
+
+#include <png.h>
+
+.SH III. Reading
+
+Reading PNG files:
+
+We'll now walk you through the possible functions to call when reading
+in a PNG file, briefly explaining the syntax and purpose of each one.
+See example.c and png.h for more detail. While Progressive reading
+is covered in the next section, you will still need some of the
+functions discussed in this section to read a PNG file.
+
+You will want to do the I/O initialization(*) before you get into libpng,
+so if it doesn't work, you don't have much to undo. Of course, you
+will also want to insure that you are, in fact, dealing with a PNG
+file. Libpng provides a simple check to see if a file is a PNG file.
+To use it, pass in the first 1 to 8 bytes of the file, and it will
+return true or false (1 or 0) depending on whether the bytes could be
+part of a PNG file. Of course, the more bytes you pass in, the
+greater the accuracy of the prediction.
+
+If you are intending to keep the file pointer open for use in libpng,
+you must ensure you don't read more than 8 bytes from the beginning
+of the file, and you also have to make a call to png_set_sig_bytes_read()
+with the number of bytes you read from the beginning. Libpng will
+then only check the bytes (if any) that your program didn't read.
+
+(*): If you are not using the standard I/O functions, you will need
+to replace them with custom functions. See the discussion under
+Customizing libpng.
+
+
+ FILE *fp = fopen(file_name, "rb");
+ if (!fp)
+ {
+ return;
+ }
+ fread(header, 1, number, fp);
+ is_png = !png_sig_cmp(header, 0, number);
+ if (!is_png)
+ {
+ return;
+ }
+
+
+Next, png_struct and png_info need to be allocated and initialized. In
+order to ensure that the size of these structures is correct even with a
+dynamically linked libpng, there are functions to initialize and
+allocate the structures. We also pass the library version, optional
+pointers to error handling functions, and a pointer to a data struct for
+use by the error functions, if necessary (the pointer and functions can
+be NULL if the default error handlers are to be used). See the section
+on Changes to Libpng below regarding the old initialization functions.
+
+ png_structp png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr,
+ (png_infopp)NULL, (png_infopp)NULL);
+ return;
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return;
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_read_struct_2() instead of png_create_read_struct():
+
+ png_structp png_ptr = png_create_read_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+The error handling routines passed to png_create_read_struct()
+and the memory alloc/free routines passed to png_create_struct_2()
+are only necessary if you are not using the libpng supplied error
+handling and memory alloc/free functions.
+
+When libpng encounters an error, it expects to longjmp back
+to your routine. Therefore, you will need to call setjmp and pass
+your png_ptr->jmpbuf. If you read the file from different
+routines, you will need to update the jmpbuf field every time you enter
+a new routine that will call a png_ function.
+
+See your documentation of setjmp/longjmp for your compiler for more
+handling in the Customizing Libpng section below for more information on
+the libpng error handling. If an error occurs, and libpng longjmp's
+back to your setjmp, you will want to call png_destroy_read_struct() to
+free any memory.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+ fclose(fp);
+ return;
+ }
+
+Now you need to set up the input code. The default for libpng is to
+use the C function fread(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. If you wish to handle reading data in another
+way, you need not call the png_init_io() function, but you must then
+implement the libpng I/O methods discussed in the Customizing Libpng
+section below.
+
+ png_init_io(png_ptr, fp);
+
+If you had previously opened the file and read any of the signature from
+the beginning in order to see if this was a PNG file, you need to let
+libpng know that there are some bytes missing from the start of the file.
+
+ png_set_sig_bytes(png_ptr, number);
+
+At this point, you can set up a callback function that will be
+called after each row has been read, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void read_row_callback(png_ptr, png_uint_32 row, int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "read_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_status_fn(png_ptr, read_row_callback);
+
+In PNG files, the alpha channel in an image is the level of opacity.
+If you need the alpha channel in an image to be the level of transparency
+instead of opacity, you can invert the alpha channel (or the tRNS chunk
+data) after it's read, so that 0 is fully opaque and 255 (in 8-bit or
+paletted images) or 65535 (in 16-bit images) is fully transparent, with
+
+ png_set_invert_alpha(png_ptr);
+
+This has to appear here rather than later with the other transformations
+because the tRNS chunk data must be modified in the case of paletted images.
+If your image is not a paletted image, the tRNS data (which in such cases
+represents a single color to be rendered as transparent) won't be changed.
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_read_user_transform_fn(png_ptr,
+ read_transform_fn);
+
+You must supply the function
+
+ void read_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+after all of the other transformations have been processed.
+
+You are now ready to read all the file information up to the actual
+image data. You do this with a call to png_read_info().
+
+ png_read_info(png_ptr, info_ptr);
+
+Functions are used to get the information from the info_ptr:
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height,
+ &bit_depth, &color_type, &interlace_type,
+ &compression_type, &filter_type);
+
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels. (valid values are
+ 1, 2, 4, 8, 16 and depend also on
+ the color_type. See also
+ significant bits (sBIT) below).
+ color_type - describes which color/alpha channels
+ are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ filter_type - (must be PNG_FILTER_TYPE_BASE
+ for PNG 1.0)
+ compression_type - (must be PNG_COMPRESSION_TYPE_BASE
+ for PNG 1.0)
+ interlace_type - (PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7)
+ Any or all of interlace_type, compression_type, of
+ filter_type can be
+ NULL if you are not interested in their values.
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ channels - number of channels of info for the
+ color type (valid values are 1 (GRAY,
+ PALETTE), 2 (GRAY_ALPHA), 3 (RGB),
+ 4 (RGB_ALPHA or RGB + filler byte))
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ rowbytes - number of bytes needed to hold a row
+
+ signature = png_get_signature(png_ptr, info_ptr);
+ signature - holds the signature read from the
+ file (if any). The data is kept in
+ the same offset it would be if the
+ whole signature were read (i.e. if an
+ application had already read in 4
+ bytes of signature before starting
+ libpng, the remaining 4 bytes would
+ be in signature[4] through signature[7]
+ (see png_set_sig_bytes())).
+
+
+ width = png_get_image_width(png_ptr,
+ info_ptr);
+ height = png_get_image_height(png_ptr,
+ info_ptr);
+ bit_depth = png_get_bit_depth(png_ptr,
+ info_ptr);
+ color_type = png_get_color_type(png_ptr,
+ info_ptr);
+ filter_type = png_get_filter_type(png_ptr,
+ info_ptr);
+ compression_type = png_get_compression_type(png_ptr,
+ info_ptr);
+ interlace_type = png_get_interlace_type(png_ptr,
+ info_ptr);
+
+
+These are also important, but their validity depends on whether the chunk
+has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and
+png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the
+data has been read, or zero if it is missing. The parameters to the
+png_get_<chunk> are set directly if they are simple data types, or a pointer
+into the info_ptr is returned for any complex types.
+
+ png_get_PLTE(png_ptr, info_ptr, &palette,
+ &num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_get_gAMA(png_ptr, info_ptr, &gamma);
+ gamma - the gamma the file is written
+ at (PNG_INFO_gAMA)
+
+ png_get_sRGB(png_ptr, info_ptr, &srgb_intent);
+ srgb_intent - the rendering intent (PNG_INFO_sRGB)
+ The presence of the sRGB chunk
+ means that the pixel data is in the
+ sRGB color space. This chunk also
+ implies specific values of gAMA and
+ cHRM.
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray,
+ red, green, and blue channels,
+ whichever are appropriate for the
+ given color type (png_color_16)
+
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
+ &trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - transparent pixel for non-paletted
+ images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_get_hIST(png_ptr, info_ptr, &hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_color_16)
+
+ png_get_tIME(png_ptr, info_ptr, &mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_get_bKGD(png_ptr, info_ptr, &background);
+ background - background color (PNG_VALID_bKGD)
+
+ num_text = png_get_text(png_ptr, info_ptr, &text_ptr);
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i]->key - keyword for comment.
+ text_ptr[i]->text - text comments for current
+ keyword.
+ text_ptr[i]->compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ or PNG_TEXT_COMPRESSION_zTXt
+ num_text - number of comments
+
+ png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y,
+ &unit_type);
+ offset_x - positive offset from the left edge
+ of the screen
+ offset_y - positive offset from the top edge
+ of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y,
+ &unit_type);
+ res_x - pixels/unit physical resolution in
+ x direction
+ res_y - pixels/unit physical resolution in
+ x direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+The data from the pHYs chunk can be retrieved in several convenient
+forms:
+
+ res_x = png_get_x_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_meter(png_ptr,
+ info_ptr)
+ aspect_ratio = png_get_pixel_aspect_ratio(png_ptr,
+ info_ptr)
+
+ (Each of these returns 0 [signifying "unknown"] if
+ the data is not present or if res_x is 0;
+ res_x_and_y is 0 if res_x != res_y)
+
+For more information, see the png_info definition in png.h and the
+PNG specification for chunk contents. Be careful with trusting
+rowbytes, as some of the transformations could increase the space
+needed to hold a row (expand, filler, gray_to_rgb, etc.).
+See png_read_update_info(), below.
+
+A quick word about text_ptr and num_text. PNG stores comments in
+keyword/text pairs, one pair per chunk, with no limit on the number
+of text chunks, and a 2^31 byte limit on their size. While there are
+suggested keywords, there is no requirement to restrict the use to these
+strings. It is strongly suggested that keywords and text be sensible
+to humans (that's the point), so don't use abbreviations. Non-printing
+symbols are not allowed. See the PNG specification for more details.
+There is also no requirement to have text after the keyword.
+
+Keywords should be limited to 79 Latin-1 characters without leading or
+trailing spaces, but non-consecutive spaces are allowed within the
+keyword. It is possible to have the same keyword any number of times.
+The text_ptr is an array of png_text structures, each holding pointer
+to a keyword and a pointer to a text string. Only the text string may
+be null. The keyword/text pairs are put into the array in the order
+that they are received. However, some or all of the text chunks may be
+after the image, so, to make sure you have read all the text chunks,
+don't mess with these until after you read the stuff after the image.
+This will be mentioned again below in the discussion that goes with
+png_read_end().
+
+After you've read the header information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+The colors used for the background and transparency values should be
+supplied in the same format/depth as the current image data. They
+are stored in the same format/depth as the image data in a bKGD or tRNS
+chunk, so this is what libpng expects for this data. The colors are
+transformed to keep in sync with the image data when an application
+calls the png_read_update_info() routine (see below).
+
+Data will be decoded into the supplied row buffers packed into bytes
+unless the library has been told to transform it into another format.
+For example, 4 bit/pixel paletted or grayscale data will be returned
+2 pixels/byte with the leftmost pixel in the high-order bits of the
+byte, unless png_set_packing() is called. 8-bit RGB data will be stored
+in RGB RGB RGB format unless png_set_filler() is called to insert filler
+bytes, either before or after each RGB triplet. 16-bit RGB data will
+be returned RRGGBB RRGGBB, with the most significant byte of the color
+value first, unless png_set_strip_16() is called to transform it to
+regular RGB RGB triplets, or png_set_filler() is called to insert
+filler bytes, either before or after each RRGGBB triplet. Similarly,
+8-bit or 16-bit grayscale data can be modified with png_set_filler()
+or png_set_strip_16().
+
+The following code transforms grayscale images of less than 8 to 8 bits,
+changes paletted images to RGB, and adds a full alpha channel if there is
+transparency information in a tRNS chunk. This is most useful on
+grayscale images with bit depths of 2 or 4 or if there is a multiple-image
+viewing application that wishes to treat all images in the same way.
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE &&
+ bit_depth <= 8) png_set_expand(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY &&
+ bit_depth < 8) png_set_expand(png_ptr);
+
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_tRNS)) png_set_expand(png_ptr);
+
+PNG can have files with 16 bits per channel. If you only can handle
+8 bits per channel, this will strip the pixels down to 8 bit.
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+The png_set_background() function tells libpng to composite images
+with alpha or simple transparency against the supplied background
+color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page). You
+need to tell libpng whether the color is in the gamma space of the
+display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
+(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
+that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
+know why anyone would use this, but it's here).
+
+If, for some reason, you don't need the alpha channel on an image,
+and you want to remove it rather than combining it with the background
+(but the image author certainly had in mind that you *would* combine
+it with the background, so that's what you should probably do):
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit
+files. This code expands to 1 pixel per byte without changing the
+values of the pixels:
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels
+stored in a PNG image have been "scaled" or "shifted" up to the next
+higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to
+8 bits/sample in the range [0, 255]). However, it is also possible to
+convert the PNG pixel data back to the original bit depth of the image.
+This call reduces the pixels back down to the original bit depth:
+
+ png_color_16p sig_bit;
+
+ if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
+ png_set_shift(png_ptr, sig_bit);
+
+PNG files store 3-color pixels in red, green, blue order. This code
+changes the storage of the pixels to blue, green, red:
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+PNG files store RGB pixels packed into 3 bytes. This code expands them
+into 4 bytes for windowing systems that need them in this format:
+
+ if (bit_depth == 8 && color_type ==
+ PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr,
+ filler, PNG_FILLER_BEFORE);
+
+where "filler" is the 8 or 16-bit number to fill with, and the location is
+either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether
+you want the filler before the RGB or after. This transformation
+does not affect images that already have full alpha channels.
+
+If you are reading an image with an alpha channel, and you need the
+data as ARGB instead of the normal PNG format RGBA:
+
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_swap_alpha(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
+RGB. This code will do that conversion:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+Conversely, you can convert an RGB or RGBA image to grayscale or grayscale
+with alpha. This is intended for conversion of images that really are
+gray (red == green == blue), so the function simply strips out the red
+and blue channels, leaving the green channel in the gray position.
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_rgb_to_gray(png_ptr, error_action,
+ float red_weight, float green_weight);
+
+ error_action = 1: silently do the conversion
+ error_action = 2: issue a warning if the original
+ image has any pixel where
+ red != green or red != blue
+ error_action = 3: issue an error and abort the
+ conversion if the original
+ image has any pixel where
+ red != green or red != blue
+
+ red_weight: weight of red component
+ (NULL -> default 54/256)
+ green_weight: weight of green component
+ (NULL -> default 183/256)
+
+If you have set error_action = 1 or 2, you can
+later check whether the image really was gray, after processing
+the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
+It will return a png_byte that is zero if the image was gray or
+1 if there were any non-gray pixels. bKGD and sBIT data
+will be silently converted to grayscale, using the green channel
+data, regardless of the error_action setting.
+
+With 0.0<=red_weight+green_weight<=1.0,
+the normalized graylevel is computed:
+
+ int rw = red_weight * 256;
+ int gw = green_weight * 256;
+ int bw = 256 - (rw + gw);
+ gray = (rw*red + gw*green + bw*blue)/256;
+
+The default values approximate those recommended in the Charles
+Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
+Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
+
+ Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+
+Libpng approximates this with
+
+ Y = 0.211 * R + 0.715 * G + 0.074 * B
+
+which can be expressed with integers as
+
+ Y = (54 * R + 183 * G + 19 * B)/256
+
+The calculation is done in a linear colorspace, if the image gamma
+is known.
+
+If you have a grayscale and you are using png_set_expand() to change to
+a higher bit-depth, you must either supply the background color as a gray
+value at the original file bit-depth (need_expand = 1) or else supply the
+background color as an RGB triplet at the final, expanded bit depth
+(need_expand = 0). Similarly, if you are reading a paletted image, you
+must either supply the background color as a palette index (need_expand = 1)
+or as an RGB triplet that may or may not be in the palette (need_expand = 0).
+
+ png_color_16 my_background;
+ png_color_16p image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+To properly display PNG images on any kind of system, the application needs
+to know what the display gamma is. Ideally, the user will know this, and
+the application will allow them to set it. One method of allowing the user
+to set the display gamma separately for each system is to check for the
+DISPLAY_GAMMA and VIEWING_GAMMA environment variables or for a SCREEN_GAMMA
+environment variable, which will hopefully be correctly set.
+
+Note that display_gamma is the gamma of your display, while screen_gamma is
+the overall gamma correction required to produce pleasing results,
+which depends on the lighting conditions in the surrounding environment.
+Screen_gamma is display_gamma/viewing_gamma, where viewing_gamma is
+the amount of additional gamma correction needed to compensate for
+a (viewing_gamma=1.25) environment. In a dim or brightly lit room, no
+compensation other than the display_gamma is needed (viewing_gamma=1.0).
+
+ if (/* We have a user-defined screen
+ gamma value */)
+ {
+ screen_gamma = user_defined_screen_gamma;
+ }
+ /* One way that applications can share the same
+ screen gamma value */
+ else if ((gamma_str = getenv("SCREEN_GAMMA"))
+ != NULL)
+ {
+ screen_gamma = atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for a
+ PC monitor in a bright office or a dim room */
+ screen_gamma = 2.0; /* A good guess for a
+ PC monitor in a dark room */
+ screen_gamma = 1.7 or 1.0; /* A good
+ guess for Mac systems */
+ }
+
+The png_set_gamma() function handles gamma transformations of the data.
+Pass both the file gamma and the current screen_gamma. If the file does
+not have a gamma value, you can pass one anyway if you have an idea what
+it is (usually 0.45455 is a good guess for GIF images on PCs). Note
+that file gammas are inverted from screen gammas. See the discussions
+on gamma in the PNG specification for an excellent description of what
+gamma is, and why all applications should support it. It is strongly
+recommended that PNG viewers support gamma correction.
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, screen_gamma, gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+
+If you need to reduce an RGB file to a paletted file, or if a paletted
+file has more entries then will fit on your screen, png_set_dither()
+will do that. Note that this is a simple match dither that merely
+finds the closest color available. This should work fairly well with
+optimized palettes, and fairly badly with linear color cubes. If you
+pass a palette that is larger then maximum_colors, the file will
+reduce the number of colors in the palette so it will fit into
+maximum_colors. If there is a histogram, it will use it to make
+more intelligent choices when reducing the palette. If there is no
+histogram, it may not do as good a job.
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_PLTE))
+ {
+ png_color_16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr,
+ &histogram);
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 1);
+ }
+ else
+ {
+ png_color std_color_cube[MAX_SCREEN_COLORS] =
+ { ... colors ... };
+
+ png_set_dither(png_ptr, std_color_cube,
+ MAX_SCREEN_COLORS, MAX_SCREEN_COLORS,
+ NULL,0);
+ }
+ }
+
+PNG files describe monochrome as black being zero and white being one.
+The following code will reverse this (make black be one and white be
+zero):
+
+ if (bit_depth == 1 && color_type == PNG_COLOR_GRAY)
+ png_set_invert_mono(png_ptr);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code changes the storage to the
+other way (little-endian, i.e. least significant bits first, the
+way PCs store them):
+
+ if (bit_depth == 16)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+The last thing to handle is interlacing; this is covered in detail below,
+but you must call the function here if you want libpng to handle expansion
+of the interlaced image.
+
+ number_of_passes = png_set_interlace_handling(png_ptr);
+
+After setting the transformations, libpng can update your png_info
+structure to reflect any transformations you've requested with this
+call. This is most useful to update the info structure's rowbytes
+field so you can use it to allocate your image memory. This function
+will also update your palette with the correct screen_gamma and
+background if these have been given with the calls above.
+
+ png_read_update_info(png_ptr, info_ptr);
+
+After you call png_read_update_info(), you can allocate any
+memory you need to hold the image. The row data is simply
+raw byte data for all forms of images. As the actual allocation
+varies among applications, no example will be given. If you
+are allocating one large chunk, you will need to build an
+array of pointers to each row, as it will be needed for some
+of the functions below.
+
+After you've allocated memory, you can read the image data.
+The simplest way to do this is in one function call. If you are
+allocating enough memory to hold the whole image, you can just
+call png_read_image() and libpng will read in all the image data
+and put it in the memory area supplied. You will need to pass in
+an array of pointers to each row.
+
+This function automatically handles interlacing, so you don't need
+to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_read_rows().
+
+ png_read_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_bytep row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to read in the whole image at once, you can
+use png_read_rows() instead. If there is no interlacing (check
+interlace_type == PNG_INTERLACE_NONE), this is simple:
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+where row_pointers is the same as in the png_read_image() call.
+
+If you are doing this just one row at a time, you can do this with
+row_pointers:
+
+ png_bytep row_pointers = row;
+ png_read_row(png_ptr, &row_pointers, NULL);
+
+If the file is interlaced (info_ptr->interlace_type != 0), things get
+somewhat harder. The only current (PNG Specification version 1.0)
+interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7)
+is a somewhat complicated 2D interlace scheme, known as Adam7, that
+breaks down an image into seven smaller images of varying size, based
+on an 8x8 grid.
+
+libpng can fill out those images or it can give them to you "as is".
+If you want them filled out, there are two ways to do that. The one
+mentioned in the PNG specification is to expand each pixel to cover
+those pixels that have not been read yet (the "rectangle" method).
+This results in a blocky image for the first pass, which gradually
+smooths out as more pixels are read. The other method is the "sparkle"
+method, where pixels are drawn only in their final locations, with the
+rest of the image remaining whatever colors they were initialized to
+before the start of the read. The first method usually looks better,
+but tends to be slower, as there are more pixels to put in the rows.
+
+If you don't want libpng to handle the interlacing details, just call
+png_read_rows() seven times to read in all seven images. Each of the
+images is a valid image by itself, or they can all be combined on an
+8x8 grid to form a single image (although if you intend to combine them
+you would be far better off using the libpng interlace handling).
+
+The first pass will return an image 1/8 as wide as the entire image
+(every 8th column starting in column 0) and 1/8 as high as the original
+(every 8th row starting in row 0), the second will be 1/8 as wide
+(starting in column 4) and 1/8 as high (also starting in row 0). The
+third pass will be 1/4 as wide (every 4th pixel starting in column 0) and
+1/8 as high (every 8th row starting in row 4), and the fourth pass will
+be 1/4 as wide and 1/4 as high (every 4th column starting in column 2,
+and every 4th row starting in row 0). The fifth pass will return an
+image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2),
+while the sixth pass will be 1/2 as wide and 1/2 as high as the original
+(starting in column 1 and row 0). The seventh and final pass will be as
+wide as the original, and 1/2 as high, containing all of the odd
+numbered scanlines. Phew!
+
+If you want libpng to expand the images, call this before calling
+png_start_read_image() or png_read_update_info():
+
+ if (interlace_type == PNG_INTERLACE_ADAM7)
+ number_of_passes
+ = png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+This function can be called even if the file is not interlaced,
+where it will return one pass.
+
+If you are not going to display the image after each pass, but are
+going to wait until the entire image is read in, use the sparkle
+effect. This effect is faster and the end result of either method
+is exactly the same. If you are planning on displaying the image
+after each pass, the "rectangle" effect is generally considered the
+better looking one.
+
+If you only want the "sparkle" effect, just call png_read_rows() as
+normal, with the third parameter NULL. Make sure you make pass over
+the image number_of_passes times, and you don't change the data in the
+rows between calls. You can change the locations of the data, just
+not the data. Each pass only writes the pixels appropriate for that
+pass, and assumes the data from previous passes is still valid.
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+If you only want the first effect (the rectangles), do the same as
+before except pass the row buffer in the third parameter, and leave
+the second parameter NULL.
+
+ png_read_rows(png_ptr, NULL, row_pointers,
+ number_of_rows);
+
+After you are finished reading the image, you can finish reading
+the file. If you are interested in comments or time, which may be
+stored either before or after the image data, you should pass the
+separate png_info struct if you want to keep the comments from
+before and after the image separate. If you are not interested, you
+can pass NULL.
+
+ png_read_end(png_ptr, end_info);
+
+When you are done, you can free all memory allocated by libpng like this:
+
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+
+For a more compact example of reading a PNG image, see the file example.c.
+
+
+Reading PNG files progressively:
+
+The progressive reader is slightly different then the non-progressive
+reader. Instead of calling png_read_info(), png_read_rows(), and
+png_read_end(), you make one call to png_process_data(), which calls
+callbacks when it has the info, a row, or the end of the image. You
+set up these callbacks with png_set_progressive_read_fn(). You don't
+have to worry about the input/output functions of libpng, as you are
+giving the library the data directly in png_process_data(). I will
+assume that you have read the section on reading PNG files above,
+so I will only highlight the differences (although I will show
+all of the code).
+
+png_structp png_ptr;
+png_infop info_ptr;
+
+ /* An example code fragment of how you would
+ initialize the progressive reader in your
+ application. */
+ int
+ initialize_png_reader()
+ {
+ png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return -1;
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
+ (png_infopp)NULL);
+ return -1;
+ }
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return -1;
+ }
+
+ /* This one's new. You can provide functions
+ to be called when the header info is valid,
+ when each row is completed, and when the image
+ is finished. If you aren't using all functions,
+ you can specify NULL parameters. Even when all
+ three functions are NULL, you need to call
+ png_set_progressive_read_fn(). You can use
+ any struct as the user_ptr (cast to a void pointer
+ for the function call), and retrieve the pointer
+ from inside the callbacks using the function
+
+ png_get_progressive_ptr(png_ptr);
+
+ which will return a void pointer, which you have
+ to cast appropriately.
+ */
+ png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
+ info_callback, row_callback, end_callback);
+
+ return 0;
+ }
+
+ /* A code fragment that you call as you receive blocks
+ of data */
+ int
+ process_data(png_bytep buffer, png_uint_32 length)
+ {
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return -1;
+ }
+
+ /* This one's new also. Simply give it a chunk
+ of data from the file stream (in order, of
+ course). On machines with segmented memory
+ models machines, don't give it any more than
+ 64K. The library seems to run fine with sizes
+ of 4K. Although you can give it much less if
+ necessary (I assume you can give it chunks of
+ 1 byte, I haven't tried less then 256 bytes
+ yet). When this function returns, you may
+ want to display any rows that were generated
+ in the row callback if you don't already do
+ so there.
+ */
+ png_process_data(png_ptr, info_ptr, buffer, length);
+ return 0;
+ }
+
+ /* This function is called (as set by
+ png_set_progressive_read_fn() above) when enough data
+ has been supplied so all of the header has been
+ read.
+ */
+ void
+ info_callback(png_structp png_ptr, png_infop info)
+ {
+ /* Do any setup here, including setting any of
+ the transformations mentioned in the Reading
+ PNG files section. For now, you _must_ call
+ either png_start_read_image() or
+ png_read_update_info() after all the
+ transformations are set (even if you don't set
+ any). You may start getting rows before
+ png_process_data() returns, so this is your
+ last chance to prepare for that.
+ */
+ }
+
+ /* This function is called when each row of image
+ data is complete */
+ void
+ row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+ {
+ /* If the image is interlaced, and you turned
+ on the interlace handler, this function will
+ be called for every row in every pass. Some
+ of these rows will not be changed from the
+ previous pass. When the row is not changed,
+ the new_row variable will be NULL. The rows
+ and passes are called in order, so you don't
+ really need the row_num and pass, but I'm
+ supplying them because it may make your life
+ easier.
+
+ For the non-NULL rows of interlaced images,
+ you must call png_progressive_combine_row()
+ passing in the row and the old row. You can
+ call this function for NULL rows (it will just
+ return) and for non-interlaced images (it just
+ does the memcpy for you) if it will make the
+ code easier. Thus, you can just do this for
+ all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row,
+ new_row);
+
+ /* where old_row is what was displayed for
+ previously for the row. Note that the first
+ pass (pass == 0, really) will completely cover
+ the old row, so the rows do not have to be
+ initialized. After the first pass (and only
+ for interlaced images), you will have to pass
+ the current row, and the function will combine
+ the old row and the new row.
+ */
+ }
+
+ void
+ end_callback(png_structp png_ptr, png_infop info)
+ {
+ /* This function is called after the whole image
+ has been read, including any chunks after the
+ image (up to and including the IEND). You
+ will usually have the same info chunk as you
+ had in the header, although some data may have
+ been added to the comments and time fields.
+
+ Most people won't do much here, perhaps setting
+ a flag that marks the image as finished.
+ */
+ }
+
+
+
+.SH IV. Writing
+
+Much of this is very similar to reading. However, everything of
+importance is repeated here, so you won't have to constantly look
+back up in the reading section to understand writing.
+
+You will want to do the I/O initialization before you get into libpng,
+so if it doesn't work, you don't have anything to undo. If you are not
+using the standard I/O functions, you will need to replace them with
+custom writing functions. See the discussion under Customizing libpng.
+
+ FILE *fp = fopen(file_name, "wb");
+ if (!fp)
+ {
+ return;
+ }
+
+Next, png_struct and png_info need to be allocated and initialized.
+As these can be both relatively large, you may not want to store these
+on the stack, unless you have stack space to spare. Of course, you
+will want to check if they return NULL. If you are also reading,
+you won't want to name your read structure and your write structure
+both "png_ptr"; you can call them anything you like, such as
+"read_ptr" and "write_ptr". Look at pngtest.c, for example.
+
+ png_structp png_ptr = png_create_write_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr,
+ (png_infopp)NULL);
+ return;
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_write_struct_2() instead of png_create_read_struct():
+
+ png_structp png_ptr = png_create_write_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+After you have these structures, you will need to set up the
+error handling. When libpng encounters an error, it expects to
+longjmp() back to your routine. Therefore, you will need to call
+setjmp() and pass the png_ptr->jmpbuf. If you
+write the file from different routines, you will need to update
+the jmpbuf field every time you enter a new routine that will
+call a png_ function. See your documentation of setjmp/longjmp
+for your compiler for more information on setjmp/longjmp. See
+the discussion on libpng error handling in the Customizing Libpng
+section below for more information on the libpng error handling.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return;
+ }
+ ...
+ return;
+
+Now you need to set up the output code. The default for libpng is to
+use the C function fwrite(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. Again, if you wish to handle writing data in
+another way, see the discussion on libpng I/O handling in the Customizing
+Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+At this point, you can set up a callback function that will be
+called after each row has been written, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void write_row_callback(png_ptr, png_uint_32 row, int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "write_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_write_status_fn(png_ptr, write_row_callback);
+
+You now have the option of modifying how the compression library will
+run. The following functions are mainly for testing, but may be useful
+in some cases, like if you need to write PNG files extremely fast and
+are willing to give up some compression, or if you want to get the
+maximum possible compression at the expense of slower writing. If you
+have no special needs in this area, let the library do what it wants by
+not calling this function at all, as it has been tuned to deliver a good
+speed/compression ratio. The second parameter to png_set_filter() is
+the filter method, for which the only valid value is '0' (as of the
+October 1996 PNG specification, version 1.0). The third parameter is a
+flag that indicates which filter type(s) are to be tested for each
+scanline. See the Compression Library for details on the specific filter
+types.
+
+
+ /* turn on or off filtering, and/or choose
+ specific filters */
+ png_set_filter(png_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_SUB |
+ PNG_FILTER_PAETH);
+
+The png_set_compression_???() functions interface to the zlib compression
+library, and should mostly be ignored unless you really know what you are
+doing. The only generally useful call is png_set_compression_level()
+which changes how much time zlib spends on trying to compress the image
+data. See the Compression Library for details on the compression levels.
+
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr,
+ Z_BEST_COMPRESSION);
+
+ /* set other zlib parameters */
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_strategy(png_ptr,
+ Z_DEFAULT_STRATEGY);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+
+You now need to fill in the png_info structure with all the data you
+wish to write before the actual image. Note that the only thing you
+are allowed to write after the image is the text chunks and the time
+chunk (as of PNG Specification 1.0, anyway). See png_write_end() and
+the latest PNG specification for more information on that. If you
+wish to write them before the image, fill them in now, and flag that
+data as being valid. If you want to wait until after the data, don't
+fill them until png_write_end(). For all the fields in png_info and
+their data types, see png.h. For explanations of what the fields
+contain, see the PNG specification.
+
+Some of the more important parts of the png_info are:
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ bit_depth, color_type, interlace_type,
+ compression_type, filter_type)
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels.
+ (valid values are 1, 2, 4, 8, 16
+ and depend also on the
+ color_type. See also significant
+ bits (sBIT) below).
+ color_type - describes which color/alpha
+ channels are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ interlace_type - PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7
+ compression_type - (must be
+ PNG_COMPRESSION_TYPE_DEFAULT)
+ filter_type - (must be PNG_FILTER_TYPE_DEFAULT)
+
+ png_set_PLTE(png_ptr, info_ptr, palette,
+ num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ gamma - the gamma the image was created
+ at (PNG_INFO_gAMA)
+
+ png_set_sRGB(png_ptr, info_ptr, srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of
+ the sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This chunk also implies specific
+ values of gAMA and cHRM. Rendering
+ intent is the CSS-1 property that
+ has been defined by the International
+ Color Consortium
+ (http://www.color.org).
+ It can be one of
+ PNG_SRGB_INTENT_SATURATION,
+ PNG_SRGB_INTENT_PERCEPTUAL,
+ PNG_SRGB_INTENT_ABSOLUTE, or
+ PNG_SRGB_INTENT_RELATIVE.
+
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
+ srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of the
+ sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This function also causes gAMA and
+ cHRM chunks with the specific values
+ that are consistent with sRGB to be
+ written.
+
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray, red,
+ green, and blue channels, whichever are
+ appropriate for the given color type
+ (png_color_16)
+
+ png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
+ trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - transparent pixel for non-paletted
+ images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_set_hIST(png_ptr, info_ptr, hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_color_16)
+
+ png_set_tIME(png_ptr, info_ptr, mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_set_bKGD(png_ptr, info_ptr, background);
+ background - background color (PNG_VALID_bKGD)
+
+ png_set_text(png_ptr, info_ptr, text_ptr, num_text);
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i]->key - keyword for comment.
+ text_ptr[i]->text - text comments for current
+ keyword.
+ text_ptr[i]->compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE or
+ PNG_TEXT_COMPRESSION_zTXt
+ num_text - number of comments in text_ptr
+
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y,
+ unit_type);
+ offset_x - positive offset from the left
+ edge of the screen
+ offset_y - positive offset from the top
+ edge of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
+ unit_type);
+ res_x - pixels/unit physical resolution
+ in x direction
+ res_y - pixels/unit physical resolution
+ in y direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+In PNG files, the alpha channel in an image is the level of opacity.
+If your data is supplied as a level of transparency, you can invert the
+alpha channel before you write it, so that 0 is fully transparent and 255
+(in 8-bit or paletted images) or 65535 (in 16-bit images) is fully opaque,
+with
+
+ png_set_invert_alpha(png_ptr);
+
+This must appear here instead of later with the other transformations
+because in the case of paletted images the tRNS chunk data has to
+be inverted before the tRNS chunk is written. If your image is not a
+paletted image, the tRNS data (which in such cases represents a single
+color to be rendered as transparent) won't be changed.
+
+A quick word about text and num_text. text is an array of png_text
+structures. num_text is the number of valid structures in the array.
+If you want, you can use max_text to hold the size of the array, but
+libpng ignores it for writing (it does use it for reading). Each
+png_text structure holds a keyword-text value, and a compression type.
+The compression types have the same valid numbers as the compression
+types of the image data. Currently, the only valid number is zero.
+However, you can store text either compressed or uncompressed, unlike
+images, which always have to be compressed. So if you don't want the
+text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE.
+Until text gets around 1000 bytes, it is not worth compressing it.
+After the text has been written out to the file, the compression type
+is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR,
+so that it isn't written out again at the end (in case you are calling
+png_write_end() with the same struct.
+
+The keywords that are given in the PNG Specification are:
+
+ Title Short (one line) title or
+ caption for image
+ Author Name of image's creator
+ Description Description of image (possibly long)
+ Copyright Copyright notice
+ Creation Time Time of original image creation
+ (usually RFC 1123 format, see below)
+ Software Software used to create the image
+ Disclaimer Legal disclaimer
+ Warning Warning of nature of content
+ Source Device used to create the image
+ Comment Miscellaneous comment; conversion
+ from other image format
+
+The keyword-text pairs work like this. Keywords should be short
+simple descriptions of what the comment is about. Some typical
+keywords are found in the PNG specification, as is some recommendations
+on keywords. You can repeat keywords in a file. You can even write
+some text before the image and some after. For example, you may want
+to put a description of the image before the image, but leave the
+disclaimer until after, so viewers working over modem connections
+don't have to wait for the disclaimer to go over the modem before
+they start seeing the image. Finally, keywords should be full
+words, not abbreviations. Keywords and text are in the ISO 8859-1
+(Latin-1) character set (a superset of regular ASCII) and can not
+contain NUL characters, and should not contain control or other
+unprintable characters. To make the comments widely readable, stick
+with basic ASCII, and avoid machine specific character set extensions
+like the IBM-PC character set. The keyword must be present, but
+you can leave off the text string on non-compressed pairs.
+Compressed pairs must have a text string, as only the text string
+is compressed anyway, so the compression would be meaningless.
+
+PNG supports modification time via the png_time structure. Two
+conversion routines are proved, png_convert_from_time_t() for
+time_t and png_convert_from_struct_tm() for struct tm. The
+time_t routine uses gmtime(). You don't have to use either of
+these, but if you wish to fill in the png_time structure directly,
+you should provide the time in universal time (GMT) if possible
+instead of your local time. Note that the year number is the full
+year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and
+that months start with 1.
+
+If you want to store the time of the original image creation, you should
+use a plain tEXt chunk with the "Creation Time" keyword. This is
+necessary because the "creation time" of a PNG image is somewhat vague,
+depending on whether you mean the PNG file, the time the image was
+created in a non-PNG format, a still photo from which the image was
+scanned, or possibly the subject matter itself. In order to facilitate
+machine-readable dates, it is recommended that the "Creation Time"
+tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"),
+although this isn't a requirement. Unlike the tIME chunk, the
+"Creation Time" tEXt chunk is not expected to be automatically changed
+by the software. To facilitate the use of RFC 1123 dates, a function
+png_convert_to_rfc1123(png_timep) is provided to convert from PNG
+time to an RFC 1123 format string.
+
+You are now ready to write all the file information up to the actual
+image data. You do this with a call to png_write_info().
+
+ png_write_info(png_ptr, info_ptr);
+
+After you've written the file information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code tells
+the library to expand the input data to 4 or 8 bytes per pixel
+(or expand 1 or 2-byte grayscale data to 2 or 4 bytes per pixel).
+
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+where the 0 is the value that will be put in the 4th byte, and the
+location is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending
+upon whether the filler byte is stored XRGB or RGBX.
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit files.
+If the data is supplied at 1 pixel per byte, use this code, which will
+correctly pack the pixels into a single byte:
+
+ png_set_packing(png_ptr);
+
+PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your
+data is of another bit depth, you can write an sBIT chunk into the
+file so that decoders can get the original data if desired.
+
+ /* Set the true bit depth of the image data */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit.red = true_bit_depth;
+ sig_bit.green = true_bit_depth;
+ sig_bit.blue = true_bit_depth;
+ }
+ else
+ {
+ sig_bit.gray = true_bit_depth;
+ }
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ sig_bit.alpha = true_bit_depth;
+ }
+
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+If the data is stored in the row buffer in a bit depth other than
+one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG),
+this will scale the values to appear to be the correct bit depth as
+is required by PNG.
+
+ png_set_shift(png_ptr, &sig_bit);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code would be used if they are
+supplied the other way (little-endian, i.e. least significant bits
+first, the way PCs store them):
+
+ if (bit_depth > 8)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. This code
+would be used if they are supplied as blue, green, red:
+
+ png_set_bgr(png_ptr);
+
+PNG files describe monochrome as black being zero and white being
+one. This code would be used if the pixels are supplied with this reversed
+(black being one and white being zero):
+
+ png_set_invert_mono(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_write_user_transform_fn(png_ptr,
+ write_transform_fn);
+
+You must supply the function
+
+ void write_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+before any of the other transformations have been processed.
+
+It is possible to have libpng flush any pending output, either manually,
+or automatically after a certain number of lines have been written. To
+flush the output stream a single time call:
+
+ png_write_flush(png_ptr);
+
+and to have libpng flush the output stream periodically after a certain
+number of scanlines have been written, call:
+
+ png_set_flush(png_ptr, nrows);
+
+Note that the distance between rows is from the last time png_write_flush()
+was called, or the first row of the image if it has never been called.
+So if you write 50 lines, and then png_set_flush 25, it will flush the
+output on the next scanline, and every 25 lines thereafter, unless
+png_write_flush() is called before 25 more lines have been written.
+If nrows is too small (less than about 10 lines for a 640 pixel wide
+RGB image) the image compression may decrease noticeably (although this
+may be acceptable for real-time applications). Infrequent flushing will
+only degrade the compression performance by a few percent over images
+that do not use flushing.
+
+That's it for the transformations. Now you can write the image data.
+The simplest way to do this is in one function call. If have the
+whole image in memory, you can just call png_write_image() and libpng
+will write the image. You will need to pass in an array of pointers to
+each row. This function automatically handles interlacing, so you don't
+need to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_write_rows().
+
+ png_write_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_byte *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to write the whole image at once, you can
+use png_write_rows() instead. If the file is not interlaced,
+this is simple:
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+row_pointers is the same as in the png_write_image() call.
+
+If you are just writing one row at a time, you can do this with
+row_pointers:
+
+ png_bytep row_pointer = row;
+
+ png_write_row(png_ptr, &row_pointer);
+
+When the file is interlaced, things can get a good deal more
+complicated. The only currently (as of February 1998 -- PNG Specification
+version 1.0, dated October 1996) defined interlacing scheme for PNG files
+is the "Adam7" interlace scheme, that breaks down an
+image into seven smaller images of varying size. libpng will build
+these images for you, or you can do them yourself. If you want to
+build them yourself, see the PNG specification for details of which
+pixels to write when.
+
+If you don't want libpng to handle the interlacing details, just
+use png_set_interlace_handling() and call png_write_rows() the
+correct number of times to write all seven sub-images.
+
+If you want libpng to build the sub-images, call this before you start
+writing any rows:
+
+ number_of_passes =
+ png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+
+Then write the complete image number_of_passes times.
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+As some of these rows are not used, and thus return immediately,
+you may want to read about interlacing in the PNG specification,
+and only update the rows that are actually used.
+
+After you are finished writing the image, you should finish writing
+the file. If you are interested in writing comments or time, you should
+pass an appropriately filled png_info pointer. If you are not interested,
+you can pass NULL.
+
+ png_write_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+You must free any data you allocated for info_ptr, such as comments,
+palette, or histogram, before the call to png_destroy_write_struct();
+
+For a more compact example of writing a PNG image, see the file example.c.
+
+
+.SH V. Modifying/Customizing libpng:
+
+There are two issues here. The first is changing how libpng does
+standard things like memory allocation, input/output, and error handling.
+The second deals with more complicated things like adding new chunks,
+adding new transformations, and generally changing how libpng works.
+
+All of the memory allocation, input/output, and error handling in libpng
+goes through callbacks that are user settable. The default routines are
+in pngmem.c, pngrio.c, pngwio.c, and pngerror.c respectively. To change
+these functions, call the appropriate png_set_???_fn() function.
+
+Memory allocation is done through the functions png_large_malloc(),
+png_malloc(), png_realloc(), png_large_free(), and png_free(). These
+currently just call the standard C functions. The large functions must
+handle exactly 64K, but they don't have to handle more than that. If
+your pointers can't access more then 64K at a time, you will want to set
+MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling
+memory allocation on a platform will change between applications, these
+functions must be modified in the library at compile time.
+
+Input/Output in libpng is done through png_read() and png_write(),
+which currently just call fread() and fwrite(). The FILE * is stored in
+png_struct and is initialized via png_init_io(). If you wish to change
+the method of I/O, the library supplies callbacks that you can set
+through the function png_set_read_fn() and png_set_write_fn() at run
+time, instead of calling the png_init_io() function. These functions
+also provide a void pointer that can be retrieved via the function
+png_get_io_ptr(). For example:
+
+ png_set_read_fn(png_structp read_ptr,
+ voidp read_io_ptr, png_rw_ptr read_data_fn)
+
+ png_set_write_fn(png_structp write_ptr,
+ voidp write_io_ptr, png_rw_ptr write_data_fn,
+ png_flush_ptr output_flush_fn);
+
+ voidp read_io_ptr = png_get_io_ptr(read_ptr);
+ voidp write_io_ptr = png_get_io_ptr(write_ptr);
+
+The replacement I/O functions should have prototypes as follows:
+
+ void user_read_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_write_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_flush_data(png_structp png_ptr);
+
+Supplying NULL for the read, write, or flush functions sets them back
+to using the default C stream functions. It is an error to read from
+a write stream, and vice versa.
+
+Error handling in libpng is done through png_error() and png_warning().
+Errors handled through png_error() are fatal, meaning that png_error()
+should never return to its caller. Currently, this is handled via
+setjmp() and longjmp(), but you could change this to do things like
+exit() if you should wish. On non-fatal errors, png_warning() is called
+to print a warning message, and then control returns to the calling code.
+By default png_error() and png_warning() print a message on stderr via
+fprintf() unless the library is compiled with PNG_NO_STDIO defined. If
+you wish to change the behavior of the error functions, you will need to
+set up your own message callbacks. These functions are normally supplied
+at the time that the png_struct is created. It is also possible to change
+these functions after png_create_???_struct() has been called by calling:
+
+ png_set_error_fn(png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warning_fn);
+
+ png_voidp error_ptr = png_get_error_ptr(png_ptr);
+
+If NULL is supplied for either error_fn or warning_fn, then the libpng
+default function will be used, calling fprintf() and/or longjmp() if a
+problem is encountered. The replacement error functions should have
+parameters as follows:
+
+ void user_error_fn(png_structp png_ptr,
+ png_const_charp error_msg);
+ void user_warning_fn(png_structp png_ptr,
+ png_const_charp warning_msg);
+
+The motivation behind using setjmp() and longjmp() is the C++ throw and
+catch exception handling methods. This makes the code much easier to write,
+as there is no need to check every return code of every function call.
+However, there are some uncertainties about the status of local variables
+after a longjmp, so the user may want to be careful about doing anything after
+setjmp returns non-zero besides returning itself. Consult your compiler
+documentation for more details.
+
+If you need to read or write custom chunks, you will need to get deeper
+into the libpng code, as a mechanism has not yet been supplied for user
+callbacks with custom chunks. First, read the PNG specification, and have
+a first level of understanding of how it works. Pay particular attention
+to the sections that describe chunk names, and look at how other chunks
+were designed, so you can do things similarly. Second, check out the
+sections of libpng that read and write chunks. Try to find a chunk that
+is similar to yours and copy off of it. More details can be found in the
+comments inside the code. A way of handling unknown chunks in a generic
+method, potentially via callback functions, would be best.
+
+If you wish to write your own transformation for the data, look through
+the part of the code that does the transformations, and check out some of
+the simpler ones to get an idea of how they work. Try to find a similar
+transformation to the one you want to add and copy off of it. More details
+can be found in the comments inside the code itself.
+
+Configuring for 16 bit platforms:
+
+You may need to change the png_large_malloc() and png_large_free()
+routines in pngmem.c, as these are required to allocate 64K, although
+there is already support for many of the common DOS compilers. Also,
+you will want to look into zconf.h to tell zlib (and thus libpng) that
+it cannot allocate more then 64K at a time. Even if you can, the memory
+won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K.
+
+Configuring for DOS:
+
+For DOS users who only have access to the lower 640K, you will
+have to limit zlib's memory usage via a png_set_compression_mem_level()
+call. See zlib.h or zconf.h in the zlib library for more information.
+
+Configuring for Medium Model:
+
+Libpng's support for medium model has been tested on most of the popular
+compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets
+defined, and FAR gets defined to far in pngconf.h, and you should be
+all set. Everything in the library (except for zlib's structure) is
+expecting far data. You must use the typedefs with the p or pp on
+the end for pointers (or at least look at them and be careful). Make
+note that the row's of data are defined as png_bytepp, which is an
+unsigned char far * far *.
+
+Configuring for gui/windowing platforms:
+
+You will need to write new error and warning functions that use the GUI
+interface, as described previously, and set them to be the error and
+warning functions at the time that png_create_???_struct() is called,
+in order to have them available during the structure initialization.
+They can be changed later via png_set_error_fn(). On some compilers,
+you may also have to change the memory allocators (png_malloc, etc.).
+
+Configuring for compiler xxx:
+
+All includes for libpng are in pngconf.h. If you need to add/change/delete
+an include, this is the place to do it. The includes that are not
+needed outside libpng are protected by the PNG_INTERNAL definition,
+which is only defined for those routines inside libpng itself. The
+files in libpng proper only include png.h, which includes pngconf.h.
+
+Configuring zlib:
+
+There are special functions to configure the compression. Perhaps the
+most useful one changes the compression level, which currently uses
+input compression values in the range 0 - 9. The library normally
+uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests
+have shown that for a large majority of images, compression values in
+the range 3-6 compress nearly as well as higher levels, and do so much
+faster. For online applications it may be desirable to have maximum speed
+(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also
+specify no compression (Z_NO_COMPRESSION = 0), but this would create
+files larger than just storing the raw bitmap. You can specify the
+compression level by calling:
+
+ png_set_compression_level(png_ptr, level);
+
+Another useful one is to reduce the memory level used by the library.
+The memory level defaults to 8, but it can be lowered if you are
+short on memory (running DOS, for example, where you only have 640K).
+
+ png_set_compression_mem_level(png_ptr, level);
+
+The other functions are for configuring zlib. They are not recommended
+for normal use and may result in writing an invalid PNG file. See
+zlib.h for more information on what these mean.
+
+ png_set_compression_strategy(png_ptr,
+ strategy);
+ png_set_compression_window_bits(png_ptr,
+ window_bits);
+ png_set_compression_method(png_ptr, method);
+
+Controlling row filtering:
+
+If you want to control whether libpng uses filtering or not, which
+filters are used, and how it goes about picking row filters, you
+can call one of these functions. The selection and configuration
+of row filters can have a significant impact on the size and
+encoding speed and a somewhat lesser impact on the decoding speed
+of an image. Filtering is enabled by default for RGB and grayscale
+images (with and without alpha), but not for paletted images nor
+for any images with bit depths less than 8 bits/pixel.
+
+The 'method' parameter sets the main filtering method, which is
+currently only '0' in the PNG 1.0 specification. The 'filters'
+parameter sets which filter(s), if any, should be used for each
+scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS
+to turn filtering on and off, respectively.
+
+Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB,
+PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise
+ORed together '|' to specify one or more filters to use. These
+filters are described in more detail in the PNG specification. If
+you intend to change the filter type during the course of writing
+the image, you should start with flags set for all of the filters
+you intend to use so that libpng can initialize its internal
+structures appropriately for all of the filter types.
+
+ filters = PNG_FILTER_NONE | PNG_FILTER_SUB
+ | PNG_FILTER_UP;
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
+ filters);
+
+It is also possible to influence how libpng chooses from among the
+available filters. This is done in two ways - by telling it how
+important it is to keep the same filter for successive rows, and
+by telling it the relative computational costs of the filters.
+
+ double weights[3] = {1.5, 1.3, 1.1},
+ costs[PNG_FILTER_VALUE_LAST] =
+ {1.0, 1.3, 1.3, 1.5, 1.7};
+
+ png_set_filter_selection(png_ptr,
+ PNG_FILTER_SELECTION_WEIGHTED, 3,
+ weights, costs);
+
+The weights are multiplying factors that indicate to libpng that the
+row filter should be the same for successive rows unless another row filter
+is that many times better than the previous filter. In the above example,
+if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a
+"sum of absolute differences" 1.5 x 1.3 times higher than other filters
+and still be chosen, while the NONE filter could have a sum 1.1 times
+higher than other filters and still be chosen. Unspecified weights are
+taken to be 1.0, and the specified weights should probably be declining
+like those above in order to emphasize recent filters over older filters.
+
+The filter costs specify for each filter type a relative decoding cost
+to be considered when selecting row filters. This means that filters
+with higher costs are less likely to be chosen over filters with lower
+costs, unless their "sum of absolute differences" is that much smaller.
+The costs do not necessarily reflect the exact computational speeds of
+the various filters, since this would unduly influence the final image
+size.
+
+Note that the numbers above were invented purely for this example and
+are given only to help explain the function usage. Little testing has
+been done to find optimum values for either the costs or the weights.
+
+Removing unwanted object code:
+
+There are a bunch of #define's in pngconf.h that control what parts of
+libpng are compiled. All the defines end in _SUPPORTED. If you are
+never going to use a capability, you can change the #define to #undef
+before recompiling libpng and save yourself code and data space, or
+you can turn off individual capabilities with defines that begin with
+PNG_NO_.
+
+You can also turn all of the transforms and ancillary chunk capabilities
+off en masse with compiler directives that define
+PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS,
+or all four,
+along with directives to turn on any of the capabilities that you do
+want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable
+the extra transformations but still leave the library fully capable of reading
+and writing PNG files with all known public chunks [except for sPLT].
+Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive
+produces a library that is incapable of reading or writing ancillary chunks.
+If you are not using the progressive reading capability, you can
+turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse
+this with the INTERLACING capability, which you'll still have).
+
+All the reading and writing specific code are in separate files, so the
+linker should only grab the files it needs. However, if you want to
+make sure, or if you are building a stand alone library, all the
+reading files start with pngr and all the writing files start with
+pngw. The files that don't match either (like png.c, pngtrans.c, etc.)
+are used for both reading and writing, and always need to be included.
+The progressive reader is in pngpread.c
+
+If you are creating or distributing a dynamically linked library (a .so
+or DLL file), you should not remove or disable any parts of the library,
+as this will cause applications linked with different versions of the
+library to fail if they call functions not available in your library.
+The size of the library itself should not be an issue, because only
+those sections that are actually used will be loaded into memory.
+
+Requesting debug printout:
+
+The macro definition PNG_DEBUG can be used to request debugging
+printout. Set it to an integer value in the range 0 to 3. Higher
+numbers result in increasing amounts of debugging information. The
+information is printed to the "stderr" file, unless another file
+name is specified in the PNG_DEBUG_FILE macro definition.
+
+When PNG_DEBUG > 0, the following functions (macros) become available:
+
+ png_debug(level, message)
+ png_debug1(level, message, p1)
+ png_debug2(level, message, p1, p2)
+
+in which "level" is compared to PNG_DEBUG to decide whether to print
+the message, "message" is the formatted string to be printed,
+and p1 and p2 are parameters that are to be embedded in the string
+according to printf-style formatting directives. For example,
+
+ png_debug1(2, "foo=%d\n", foo);
+
+is expanded to
+
+ if(PNG_DEBUG > 2)
+ fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo);
+
+When PNG_DEBUG is defined but is zero, the macros aren't defined, but you
+can still use PNG_DEBUG to control your own debugging:
+
+ #ifdef PNG_DEBUG
+ fprintf(stderr, ...
+ #endif
+
+When PNG_DEBUG = 1, the macros are defined, but only png_debug statements
+having level = 0 will be printed. There aren't any such statements in
+this version of libpng, but if you insert some they will be printed.
+
+.SH VI. Changes to Libpng from version 0.88
+
+It should be noted that versions of libpng later than 0.96 are not
+distributed by the original libpng author, Guy Schalnat, nor by
+Andreas Dilger, who had taken over from Guy during 1996 and 1997, and
+distributed versions 0.89 through 0.96, but rather by another member
+of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are
+still alive and well, but they have moved on to other things.
+
+The old libpng functions png_read_init(), png_write_init(),
+png_info_init(), png_read_destroy(), and png_write_destory() have been
+moved to PNG_INTERNAL in version 0.95 to discourage their use. The
+preferred method of creating and initializing the libpng structures is
+via the png_create_read_struct(), png_create_write_struct(), and
+png_create_info_struct() because they isolate the size of the structures
+from the application, allow version error checking, and also allow the
+use of custom error handling routines during the initialization, which
+the old functions do not. The functions png_read_destroy() and
+png_write_destroy() do not actually free the memory that libpng
+allocated for these structs, but just reset the data structures, so they
+can be used instead of png_destroy_read_struct() and
+png_destroy_write_struct() if you feel there is too much system overhead
+allocating and freeing the png_struct for each image read.
+
+Setting the error callbacks via png_set_message_fn() before
+png_read_init() as was suggested in libpng-0.88 is no longer supported
+because this caused applications that do not use custom error functions
+to fail if the png_ptr was not initialized to zero. It is still possible
+to set the error callbacks AFTER png_read_init(), or to change them with
+png_set_error_fn(), which is essentially the same function, but with a
+new name to force compilation errors with applications that try to use
+the old method.
+
+.SH VII. Y2K Compliance in libpng
+
+January 13, 1999
+
+Since the PNG Development group is an ad-hoc body, we can't make
+an official declaration.
+
+This is your unofficial assurance that libpng from version 0.81 and
+upward are Y2K compliant. It is my belief that earlier versions were
+also Y2K compliant.
+
+Libpng only has three year fields. One is a 2-byte unsigned integer that
+will hold years up to 65535. The other two hold the date in text
+format, and will hold years up to 9999.
+
+The integer is
+ "png_uint_16 year" in png_time_struct.
+
+The strings are
+ "png_charp time_buffer" in png_struct and
+ "near_time_buffer", which is a local character string in png.c.
+
+There are seven time-related functions:
+
+ png_convert_to_rfc_1123() in png.c
+ (formerly png_convert_to_rfc_1152() in error)
+ png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ png_convert_from_time_t() in pngwrite.c
+ png_get_tIME() in pngget.c
+ png_handle_tIME() in pngrutil.c, called in pngread.c
+ png_set_tIME() in pngset.c
+ png_write_tIME() in pngwutil.c, called in pngwrite.c
+
+All appear to handle dates properly in a Y2K environment. The
+png_convert_from_time_t() function calls gmtime() to convert from system
+clock time, which returns (year - 1900), which we properly convert to
+the full 4-digit year. There is a possibility that applications using
+libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+function, or incorrectly passing only a 2-digit year instead of
+"year - 1900" into the png_convert_from_struct_tm() function, but this
+is not under our control. The libpng documentation has always stated
+that it works with 4-digit years, and the APIs have been documented as
+such.
+
+The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+integer to hold the year, and can hold years as large as 65535.
+
+
+ Glenn Randers-Pehrson
+ libpng maintainer
+ PNG Development Group
+
+.SH NOTE
+
+Note about libpng version numbers:
+
+Due to various miscommunications, unforeseen code incompatibilities
+and occasional factors outside the authors' control, version numbering
+on the library has not always been consistent and straightforward.
+The following table summarizes matters since version 0.89c, which was
+the first widely used release:
+
+ source png.h png.h shared-lib
+ version string int version
+ ------- ------ ------ ----------
+ 0.89c 0.89 89 1.0.89
+ 0.90 0.90 90 0.90 [should be 2.0.90]
+ 0.95 0.95 95 0.95 [should be 2.0.95]
+ 0.96 0.96 96 0.96 [should be 2.0.96]
+ 0.97b 1.00.97 97 1.0.1 [should be 2.0.97]
+ 0.97c 0.97 97 2.0.97
+ 0.98 0.98 98 2.0.98
+ 0.99 0.99 98 2.0.99
+ 0.99a-m 0.99 99 2.0.99
+ 1.00 1.00 100 2.1.0 [int should be 10000]
+ 1.0.0 1.0.0 100 2.1.0 [int should be 10000]
+ 1.0.1 1.0.1 10001 2.1.0
+
+Henceforth the source version will match the shared-library
+minor and patch numbers; the shared-library major version number will be
+used for changes in backward compatibility, as it is intended.
+The PNG_PNGLIB_VER macro, which is not used within libpng but
+is available for applications, is an unsigned integer of the form
+xyyzz corresponding to the source version x.y.z (leading zeros in y and z).
+
+.SH "SEE ALSO"
+libpngpf(3), png(5)
+.LP
+.IR libpng :
+.IP
+ftp://ftp.uu.net/graphics/png
+http://www.cdrom.com/pub/png
+
+.LP
+.IR zlib :
+.IP
+(generally) at the same location as
+.I libpng
+or at
+.br
+ftp://ftp.uu.net/pub/archiving/zip/zlib
+.br
+http://www.cdrom.com/pub/infozip/zlib
+
+.LP
+.IR PNG specification: RFC 2083
+.IP
+(generally) at the same location as
+.I libpng
+or at
+.br
+ftp://ds.internic.net/rfc/rfc2083.txt
+.br
+or (as a W3C Recommendation) at
+.br
+http://www.w3.org/TR/REC-png.html
+
+.LP
+In the case of any inconsistency between the PNG specification
+and this library, the specification takes precedence.
+
+.SH AUTHORS
+This man page: Glenn Randers-Pehrson
+<randeg@alumni.rpi.edu>
+
+Contributing Authors: John Bowler, Kevin Bracey, Sam Bushell, Andreas Dilger,
+Magnus Holmgren, Tom Lane, Dave Martindale, Glenn Randers-Pehrson,
+Greg Roelofs, Guy Eric Schalnat, Paul Schmidt, Tom Tanner, Willem van
+Schaik, Tim Wegner.
+<png-implement@dworkin.wustl.edu>
+
+The contributing authors would like to thank all those who helped
+with testing, bug fixes, and patience. This wouldn't have been
+possible without all of you.
+
+Thanks to Frank J. T. Wojcik for helping with the documentation.
+
+Libpng version 1.0.3 - January 14, 1999:
+Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc.
+Currently maintained by Glenn Randers-Pehrson (randeg@alumni.rpi.edu).
+
+Supported by the PNG development group
+.br
+(png-implement@dworkin.wustl.edu).
+
+.SH COPYRIGHT NOTICE:
+
+Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+Copyright (c) 1996, 1997 Andreas Dilger
+Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+
+The PNG Reference Library (libpng) is supplied "AS IS". The Contributing
+Authors and Group 42, Inc. disclaim all warranties, expressed or implied,
+including, without limitation, the warranties of merchantability and of
+fitness for any purpose. The Contributing Authors and Group 42, Inc.
+assume no liability for direct, indirect, incidental, special, exemplary,
+or consequential damages, which may result from the use of the PNG
+Reference Library, even if advised of the possibility of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+source code, or portions hereof, for any purpose, without fee, subject
+to the following restrictions:
+
+ 1. The origin of this source code must not be
+ misrepresented.
+
+ 2. Altered versions must be plainly marked as such
+ and must not be misrepresented as being the
+ original source.
+
+ 3. This Copyright notice may not be removed or
+ altered from any source or altered source
+ distribution.
+
+The Contributing Authors and Group 42, Inc. specifically permit, without
+fee, and encourage the use of this source code as a component to
+supporting the PNG file format in commercial products. If you use this
+source code in a product, acknowledgment is not required but would be
+appreciated.
+
+.\" end of man page
+
--- /dev/null
+libpng.txt - A description on how to use and modify libpng
+
+ libpng version 1.0.3 - January 14, 1999
+ Updated and distributed by Glenn Randers-Pehrson
+ <randeg@alumni.rpi.edu>
+ Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ For conditions of distribution and use, see copyright
+ notice in png.h.
+
+ based on:
+
+ libpng 1.0 beta 6 version 0.96 May 28, 1997
+ Updated and distributed by Andreas Dilger
+ Copyright (c) 1996, 1997 Andreas Dilger
+
+ libpng 1.0 beta 2 - version 0.88 January 26, 1996
+ For conditions of distribution and use, see copyright
+ notice in png.h. Copyright (c) 1995, 1996 Guy Eric
+ Schalnat, Group 42, Inc.
+
+ Updated/rewritten per request in the libpng FAQ
+ Copyright (c) 1995 Frank J. T. Wojcik
+ December 18, 1995 && January 20, 1996
+
+I. Introduction
+
+This file describes how to use and modify the PNG reference library
+(known as libpng) for your own use. There are five sections to this
+file: introduction, structures, reading, writing, and modification and
+configuration notes for various special platforms. In addition to this
+file, example.c is a good starting point for using the library, as
+it is heavily commented and should include everything most people
+will need. We assume that libpng is already installed; see the
+INSTALL file for instructions on how to install libpng.
+
+Libpng was written as a companion to the PNG specification, as a way
+of reducing the amount of time and effort it takes to support the PNG
+file format in application programs. The PNG specification is available
+as RFC 2083 <ftp://ftp.uu.net/graphics/png/documents/> and as a
+W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some
+additional chunks are described in the special-purpose public chunks
+documents at <ftp://ftp.uu.net/graphics/png/documents/>. Other information
+about PNG, and the latest version of libpng, can be found at the PNG home
+page, <http://www.cdrom.com/pub/png/>.
+
+Most users will not have to modify the library significantly; advanced
+users may want to modify it more. All attempts were made to make it as
+complete as possible, while keeping the code easy to understand.
+Currently, this library only supports C. Support for other languages
+is being considered.
+
+Libpng has been designed to handle multiple sessions at one time,
+to be easily modifiable, to be portable to the vast majority of
+machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
+to use. The ultimate goal of libpng is to promote the acceptance of
+the PNG file format in whatever way possible. While there is still
+work to be done (see the TODO file), libpng should cover the
+majority of the needs of its users.
+
+Libpng uses zlib for its compression and decompression of PNG files.
+Further information about zlib, and the latest version of zlib, can
+be found at the zlib home page, <http://www.cdrom.com/pub/infozip/zlib/>.
+The zlib compression utility is a general purpose utility that is
+useful for more than PNG files, and can be used without libpng.
+See the documentation delivered with zlib for more details.
+You can usually find the source files for the zlib utility wherever you
+find the libpng source files.
+
+Libpng is thread safe, provided the threads are using different
+instances of the structures. Each thread should have its own
+png_struct and png_info instances, and thus its own image.
+Libpng does not protect itself against two threads using the
+same instance of a structure.
+
+
+II. Structures
+
+There are two main structures that are important to libpng, png_struct
+and png_info. The first, png_struct, is an internal structure that
+will not, for the most part, be used by a user except as the first
+variable passed to every libpng function call.
+
+The png_info structure is designed to provide information about the
+PNG file. At one time, the fields of png_info were intended to be
+directly accessible to the user. However, this tended to cause problems
+with applications using dynamically loaded libraries, and as a result
+a set of interface functions for png_info was developed. The fields
+of png_info are still available for older applications, but it is
+suggested that applications use the new interfaces if at all possible.
+
+The png.h header file is an invaluable reference for programming with libpng.
+And while I'm on the topic, make sure you include the libpng header file:
+
+#include <png.h>
+
+III. Reading
+
+Reading PNG files:
+
+We'll now walk you through the possible functions to call when reading
+in a PNG file, briefly explaining the syntax and purpose of each one.
+See example.c and png.h for more detail. While Progressive reading
+is covered in the next section, you will still need some of the
+functions discussed in this section to read a PNG file.
+
+You will want to do the I/O initialization(*) before you get into libpng,
+so if it doesn't work, you don't have much to undo. Of course, you
+will also want to insure that you are, in fact, dealing with a PNG
+file. Libpng provides a simple check to see if a file is a PNG file.
+To use it, pass in the first 1 to 8 bytes of the file, and it will
+return true or false (1 or 0) depending on whether the bytes could be
+part of a PNG file. Of course, the more bytes you pass in, the
+greater the accuracy of the prediction.
+
+If you are intending to keep the file pointer open for use in libpng,
+you must ensure you don't read more than 8 bytes from the beginning
+of the file, and you also have to make a call to png_set_sig_bytes_read()
+with the number of bytes you read from the beginning. Libpng will
+then only check the bytes (if any) that your program didn't read.
+
+(*): If you are not using the standard I/O functions, you will need
+to replace them with custom functions. See the discussion under
+Customizing libpng.
+
+
+ FILE *fp = fopen(file_name, "rb");
+ if (!fp)
+ {
+ return;
+ }
+ fread(header, 1, number, fp);
+ is_png = !png_sig_cmp(header, 0, number);
+ if (!is_png)
+ {
+ return;
+ }
+
+
+Next, png_struct and png_info need to be allocated and initialized. In
+order to ensure that the size of these structures is correct even with a
+dynamically linked libpng, there are functions to initialize and
+allocate the structures. We also pass the library version, optional
+pointers to error handling functions, and a pointer to a data struct for
+use by the error functions, if necessary (the pointer and functions can
+be NULL if the default error handlers are to be used). See the section
+on Changes to Libpng below regarding the old initialization functions.
+
+ png_structp png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr,
+ (png_infopp)NULL, (png_infopp)NULL);
+ return;
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return;
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_read_struct_2() instead of png_create_read_struct():
+
+ png_structp png_ptr = png_create_read_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+The error handling routines passed to png_create_read_struct()
+and the memory alloc/free routines passed to png_create_struct_2()
+are only necessary if you are not using the libpng supplied error
+handling and memory alloc/free functions.
+
+When libpng encounters an error, it expects to longjmp back
+to your routine. Therefore, you will need to call setjmp and pass
+your png_ptr->jmpbuf. If you read the file from different
+routines, you will need to update the jmpbuf field every time you enter
+a new routine that will call a png_ function.
+
+See your documentation of setjmp/longjmp for your compiler for more
+handling in the Customizing Libpng section below for more information on
+the libpng error handling. If an error occurs, and libpng longjmp's
+back to your setjmp, you will want to call png_destroy_read_struct() to
+free any memory.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+ fclose(fp);
+ return;
+ }
+
+Now you need to set up the input code. The default for libpng is to
+use the C function fread(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. If you wish to handle reading data in another
+way, you need not call the png_init_io() function, but you must then
+implement the libpng I/O methods discussed in the Customizing Libpng
+section below.
+
+ png_init_io(png_ptr, fp);
+
+If you had previously opened the file and read any of the signature from
+the beginning in order to see if this was a PNG file, you need to let
+libpng know that there are some bytes missing from the start of the file.
+
+ png_set_sig_bytes(png_ptr, number);
+
+At this point, you can set up a callback function that will be
+called after each row has been read, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void read_row_callback(png_ptr, png_uint_32 row, int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "read_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_status_fn(png_ptr, read_row_callback);
+
+In PNG files, the alpha channel in an image is the level of opacity.
+If you need the alpha channel in an image to be the level of transparency
+instead of opacity, you can invert the alpha channel (or the tRNS chunk
+data) after it's read, so that 0 is fully opaque and 255 (in 8-bit or
+paletted images) or 65535 (in 16-bit images) is fully transparent, with
+
+ png_set_invert_alpha(png_ptr);
+
+This has to appear here rather than later with the other transformations
+because the tRNS chunk data must be modified in the case of paletted images.
+If your image is not a paletted image, the tRNS data (which in such cases
+represents a single color to be rendered as transparent) won't be changed.
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_read_user_transform_fn(png_ptr,
+ read_transform_fn);
+
+You must supply the function
+
+ void read_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+after all of the other transformations have been processed.
+
+You are now ready to read all the file information up to the actual
+image data. You do this with a call to png_read_info().
+
+ png_read_info(png_ptr, info_ptr);
+
+Functions are used to get the information from the info_ptr:
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height,
+ &bit_depth, &color_type, &interlace_type,
+ &compression_type, &filter_type);
+
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels. (valid values are
+ 1, 2, 4, 8, 16 and depend also on
+ the color_type. See also
+ significant bits (sBIT) below).
+ color_type - describes which color/alpha channels
+ are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ filter_type - (must be PNG_FILTER_TYPE_BASE
+ for PNG 1.0)
+ compression_type - (must be PNG_COMPRESSION_TYPE_BASE
+ for PNG 1.0)
+ interlace_type - (PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7)
+ Any or all of interlace_type, compression_type, of
+ filter_type can be
+ NULL if you are not interested in their values.
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ channels - number of channels of info for the
+ color type (valid values are 1 (GRAY,
+ PALETTE), 2 (GRAY_ALPHA), 3 (RGB),
+ 4 (RGB_ALPHA or RGB + filler byte))
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ rowbytes - number of bytes needed to hold a row
+
+ signature = png_get_signature(png_ptr, info_ptr);
+ signature - holds the signature read from the
+ file (if any). The data is kept in
+ the same offset it would be if the
+ whole signature were read (i.e. if an
+ application had already read in 4
+ bytes of signature before starting
+ libpng, the remaining 4 bytes would
+ be in signature[4] through signature[7]
+ (see png_set_sig_bytes())).
+
+
+ width = png_get_image_width(png_ptr,
+ info_ptr);
+ height = png_get_image_height(png_ptr,
+ info_ptr);
+ bit_depth = png_get_bit_depth(png_ptr,
+ info_ptr);
+ color_type = png_get_color_type(png_ptr,
+ info_ptr);
+ filter_type = png_get_filter_type(png_ptr,
+ info_ptr);
+ compression_type = png_get_compression_type(png_ptr,
+ info_ptr);
+ interlace_type = png_get_interlace_type(png_ptr,
+ info_ptr);
+
+
+These are also important, but their validity depends on whether the chunk
+has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and
+png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the
+data has been read, or zero if it is missing. The parameters to the
+png_get_<chunk> are set directly if they are simple data types, or a pointer
+into the info_ptr is returned for any complex types.
+
+ png_get_PLTE(png_ptr, info_ptr, &palette,
+ &num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_get_gAMA(png_ptr, info_ptr, &gamma);
+ gamma - the gamma the file is written
+ at (PNG_INFO_gAMA)
+
+ png_get_sRGB(png_ptr, info_ptr, &srgb_intent);
+ srgb_intent - the rendering intent (PNG_INFO_sRGB)
+ The presence of the sRGB chunk
+ means that the pixel data is in the
+ sRGB color space. This chunk also
+ implies specific values of gAMA and
+ cHRM.
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray,
+ red, green, and blue channels,
+ whichever are appropriate for the
+ given color type (png_color_16)
+
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
+ &trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - transparent pixel for non-paletted
+ images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_get_hIST(png_ptr, info_ptr, &hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_color_16)
+
+ png_get_tIME(png_ptr, info_ptr, &mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_get_bKGD(png_ptr, info_ptr, &background);
+ background - background color (PNG_VALID_bKGD)
+
+ num_text = png_get_text(png_ptr, info_ptr, &text_ptr);
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i]->key - keyword for comment.
+ text_ptr[i]->text - text comments for current
+ keyword.
+ text_ptr[i]->compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ or PNG_TEXT_COMPRESSION_zTXt
+ num_text - number of comments
+
+ png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y,
+ &unit_type);
+ offset_x - positive offset from the left edge
+ of the screen
+ offset_y - positive offset from the top edge
+ of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y,
+ &unit_type);
+ res_x - pixels/unit physical resolution in
+ x direction
+ res_y - pixels/unit physical resolution in
+ x direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+The data from the pHYs chunk can be retrieved in several convenient
+forms:
+
+ res_x = png_get_x_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_meter(png_ptr,
+ info_ptr)
+ aspect_ratio = png_get_pixel_aspect_ratio(png_ptr,
+ info_ptr)
+
+ (Each of these returns 0 [signifying "unknown"] if
+ the data is not present or if res_x is 0;
+ res_x_and_y is 0 if res_x != res_y)
+
+For more information, see the png_info definition in png.h and the
+PNG specification for chunk contents. Be careful with trusting
+rowbytes, as some of the transformations could increase the space
+needed to hold a row (expand, filler, gray_to_rgb, etc.).
+See png_read_update_info(), below.
+
+A quick word about text_ptr and num_text. PNG stores comments in
+keyword/text pairs, one pair per chunk, with no limit on the number
+of text chunks, and a 2^31 byte limit on their size. While there are
+suggested keywords, there is no requirement to restrict the use to these
+strings. It is strongly suggested that keywords and text be sensible
+to humans (that's the point), so don't use abbreviations. Non-printing
+symbols are not allowed. See the PNG specification for more details.
+There is also no requirement to have text after the keyword.
+
+Keywords should be limited to 79 Latin-1 characters without leading or
+trailing spaces, but non-consecutive spaces are allowed within the
+keyword. It is possible to have the same keyword any number of times.
+The text_ptr is an array of png_text structures, each holding pointer
+to a keyword and a pointer to a text string. Only the text string may
+be null. The keyword/text pairs are put into the array in the order
+that they are received. However, some or all of the text chunks may be
+after the image, so, to make sure you have read all the text chunks,
+don't mess with these until after you read the stuff after the image.
+This will be mentioned again below in the discussion that goes with
+png_read_end().
+
+After you've read the header information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+The colors used for the background and transparency values should be
+supplied in the same format/depth as the current image data. They
+are stored in the same format/depth as the image data in a bKGD or tRNS
+chunk, so this is what libpng expects for this data. The colors are
+transformed to keep in sync with the image data when an application
+calls the png_read_update_info() routine (see below).
+
+Data will be decoded into the supplied row buffers packed into bytes
+unless the library has been told to transform it into another format.
+For example, 4 bit/pixel paletted or grayscale data will be returned
+2 pixels/byte with the leftmost pixel in the high-order bits of the
+byte, unless png_set_packing() is called. 8-bit RGB data will be stored
+in RGB RGB RGB format unless png_set_filler() is called to insert filler
+bytes, either before or after each RGB triplet. 16-bit RGB data will
+be returned RRGGBB RRGGBB, with the most significant byte of the color
+value first, unless png_set_strip_16() is called to transform it to
+regular RGB RGB triplets, or png_set_filler() is called to insert
+filler bytes, either before or after each RRGGBB triplet. Similarly,
+8-bit or 16-bit grayscale data can be modified with png_set_filler()
+or png_set_strip_16().
+
+The following code transforms grayscale images of less than 8 to 8 bits,
+changes paletted images to RGB, and adds a full alpha channel if there is
+transparency information in a tRNS chunk. This is most useful on
+grayscale images with bit depths of 2 or 4 or if there is a multiple-image
+viewing application that wishes to treat all images in the same way.
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE &&
+ bit_depth <= 8) png_set_expand(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY &&
+ bit_depth < 8) png_set_expand(png_ptr);
+
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_tRNS)) png_set_expand(png_ptr);
+
+PNG can have files with 16 bits per channel. If you only can handle
+8 bits per channel, this will strip the pixels down to 8 bit.
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+The png_set_background() function tells libpng to composite images
+with alpha or simple transparency against the supplied background
+color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page). You
+need to tell libpng whether the color is in the gamma space of the
+display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
+(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
+that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
+know why anyone would use this, but it's here).
+
+If, for some reason, you don't need the alpha channel on an image,
+and you want to remove it rather than combining it with the background
+(but the image author certainly had in mind that you *would* combine
+it with the background, so that's what you should probably do):
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit
+files. This code expands to 1 pixel per byte without changing the
+values of the pixels:
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels
+stored in a PNG image have been "scaled" or "shifted" up to the next
+higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to
+8 bits/sample in the range [0, 255]). However, it is also possible to
+convert the PNG pixel data back to the original bit depth of the image.
+This call reduces the pixels back down to the original bit depth:
+
+ png_color_16p sig_bit;
+
+ if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
+ png_set_shift(png_ptr, sig_bit);
+
+PNG files store 3-color pixels in red, green, blue order. This code
+changes the storage of the pixels to blue, green, red:
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+PNG files store RGB pixels packed into 3 bytes. This code expands them
+into 4 bytes for windowing systems that need them in this format:
+
+ if (bit_depth == 8 && color_type ==
+ PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr,
+ filler, PNG_FILLER_BEFORE);
+
+where "filler" is the 8 or 16-bit number to fill with, and the location is
+either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether
+you want the filler before the RGB or after. This transformation
+does not affect images that already have full alpha channels.
+
+If you are reading an image with an alpha channel, and you need the
+data as ARGB instead of the normal PNG format RGBA:
+
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_swap_alpha(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
+RGB. This code will do that conversion:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+Conversely, you can convert an RGB or RGBA image to grayscale or grayscale
+with alpha. This is intended for conversion of images that really are
+gray (red == green == blue), so the function simply strips out the red
+and blue channels, leaving the green channel in the gray position.
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_rgb_to_gray(png_ptr, error_action,
+ float red_weight, float green_weight);
+
+ error_action = 1: silently do the conversion
+ error_action = 2: issue a warning if the original
+ image has any pixel where
+ red != green or red != blue
+ error_action = 3: issue an error and abort the
+ conversion if the original
+ image has any pixel where
+ red != green or red != blue
+
+ red_weight: weight of red component
+ (NULL -> default 54/256)
+ green_weight: weight of green component
+ (NULL -> default 183/256)
+
+If you have set error_action = 1 or 2, you can
+later check whether the image really was gray, after processing
+the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
+It will return a png_byte that is zero if the image was gray or
+1 if there were any non-gray pixels. bKGD and sBIT data
+will be silently converted to grayscale, using the green channel
+data, regardless of the error_action setting.
+
+With 0.0<=red_weight+green_weight<=1.0,
+the normalized graylevel is computed:
+
+ int rw = red_weight * 256;
+ int gw = green_weight * 256;
+ int bw = 256 - (rw + gw);
+ gray = (rw*red + gw*green + bw*blue)/256;
+
+The default values approximate those recommended in the Charles
+Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
+Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
+
+ Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+
+Libpng approximates this with
+
+ Y = 0.211 * R + 0.715 * G + 0.074 * B
+
+which can be expressed with integers as
+
+ Y = (54 * R + 183 * G + 19 * B)/256
+
+The calculation is done in a linear colorspace, if the image gamma
+is known.
+
+If you have a grayscale and you are using png_set_expand() to change to
+a higher bit-depth, you must either supply the background color as a gray
+value at the original file bit-depth (need_expand = 1) or else supply the
+background color as an RGB triplet at the final, expanded bit depth
+(need_expand = 0). Similarly, if you are reading a paletted image, you
+must either supply the background color as a palette index (need_expand = 1)
+or as an RGB triplet that may or may not be in the palette (need_expand = 0).
+
+ png_color_16 my_background;
+ png_color_16p image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+To properly display PNG images on any kind of system, the application needs
+to know what the display gamma is. Ideally, the user will know this, and
+the application will allow them to set it. One method of allowing the user
+to set the display gamma separately for each system is to check for the
+DISPLAY_GAMMA and VIEWING_GAMMA environment variables or for a SCREEN_GAMMA
+environment variable, which will hopefully be correctly set.
+
+Note that display_gamma is the gamma of your display, while screen_gamma is
+the overall gamma correction required to produce pleasing results,
+which depends on the lighting conditions in the surrounding environment.
+Screen_gamma is display_gamma/viewing_gamma, where viewing_gamma is
+the amount of additional gamma correction needed to compensate for
+a (viewing_gamma=1.25) environment. In a dim or brightly lit room, no
+compensation other than the display_gamma is needed (viewing_gamma=1.0).
+
+ if (/* We have a user-defined screen
+ gamma value */)
+ {
+ screen_gamma = user_defined_screen_gamma;
+ }
+ /* One way that applications can share the same
+ screen gamma value */
+ else if ((gamma_str = getenv("SCREEN_GAMMA"))
+ != NULL)
+ {
+ screen_gamma = atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for a
+ PC monitor in a bright office or a dim room */
+ screen_gamma = 2.0; /* A good guess for a
+ PC monitor in a dark room */
+ screen_gamma = 1.7 or 1.0; /* A good
+ guess for Mac systems */
+ }
+
+The png_set_gamma() function handles gamma transformations of the data.
+Pass both the file gamma and the current screen_gamma. If the file does
+not have a gamma value, you can pass one anyway if you have an idea what
+it is (usually 0.45455 is a good guess for GIF images on PCs). Note
+that file gammas are inverted from screen gammas. See the discussions
+on gamma in the PNG specification for an excellent description of what
+gamma is, and why all applications should support it. It is strongly
+recommended that PNG viewers support gamma correction.
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, screen_gamma, gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+
+If you need to reduce an RGB file to a paletted file, or if a paletted
+file has more entries then will fit on your screen, png_set_dither()
+will do that. Note that this is a simple match dither that merely
+finds the closest color available. This should work fairly well with
+optimized palettes, and fairly badly with linear color cubes. If you
+pass a palette that is larger then maximum_colors, the file will
+reduce the number of colors in the palette so it will fit into
+maximum_colors. If there is a histogram, it will use it to make
+more intelligent choices when reducing the palette. If there is no
+histogram, it may not do as good a job.
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_PLTE))
+ {
+ png_color_16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr,
+ &histogram);
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 1);
+ }
+ else
+ {
+ png_color std_color_cube[MAX_SCREEN_COLORS] =
+ { ... colors ... };
+
+ png_set_dither(png_ptr, std_color_cube,
+ MAX_SCREEN_COLORS, MAX_SCREEN_COLORS,
+ NULL,0);
+ }
+ }
+
+PNG files describe monochrome as black being zero and white being one.
+The following code will reverse this (make black be one and white be
+zero):
+
+ if (bit_depth == 1 && color_type == PNG_COLOR_GRAY)
+ png_set_invert_mono(png_ptr);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code changes the storage to the
+other way (little-endian, i.e. least significant bits first, the
+way PCs store them):
+
+ if (bit_depth == 16)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+The last thing to handle is interlacing; this is covered in detail below,
+but you must call the function here if you want libpng to handle expansion
+of the interlaced image.
+
+ number_of_passes = png_set_interlace_handling(png_ptr);
+
+After setting the transformations, libpng can update your png_info
+structure to reflect any transformations you've requested with this
+call. This is most useful to update the info structure's rowbytes
+field so you can use it to allocate your image memory. This function
+will also update your palette with the correct screen_gamma and
+background if these have been given with the calls above.
+
+ png_read_update_info(png_ptr, info_ptr);
+
+After you call png_read_update_info(), you can allocate any
+memory you need to hold the image. The row data is simply
+raw byte data for all forms of images. As the actual allocation
+varies among applications, no example will be given. If you
+are allocating one large chunk, you will need to build an
+array of pointers to each row, as it will be needed for some
+of the functions below.
+
+After you've allocated memory, you can read the image data.
+The simplest way to do this is in one function call. If you are
+allocating enough memory to hold the whole image, you can just
+call png_read_image() and libpng will read in all the image data
+and put it in the memory area supplied. You will need to pass in
+an array of pointers to each row.
+
+This function automatically handles interlacing, so you don't need
+to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_read_rows().
+
+ png_read_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_bytep row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to read in the whole image at once, you can
+use png_read_rows() instead. If there is no interlacing (check
+interlace_type == PNG_INTERLACE_NONE), this is simple:
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+where row_pointers is the same as in the png_read_image() call.
+
+If you are doing this just one row at a time, you can do this with
+row_pointers:
+
+ png_bytep row_pointers = row;
+ png_read_row(png_ptr, &row_pointers, NULL);
+
+If the file is interlaced (info_ptr->interlace_type != 0), things get
+somewhat harder. The only current (PNG Specification version 1.0)
+interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7)
+is a somewhat complicated 2D interlace scheme, known as Adam7, that
+breaks down an image into seven smaller images of varying size, based
+on an 8x8 grid.
+
+libpng can fill out those images or it can give them to you "as is".
+If you want them filled out, there are two ways to do that. The one
+mentioned in the PNG specification is to expand each pixel to cover
+those pixels that have not been read yet (the "rectangle" method).
+This results in a blocky image for the first pass, which gradually
+smooths out as more pixels are read. The other method is the "sparkle"
+method, where pixels are drawn only in their final locations, with the
+rest of the image remaining whatever colors they were initialized to
+before the start of the read. The first method usually looks better,
+but tends to be slower, as there are more pixels to put in the rows.
+
+If you don't want libpng to handle the interlacing details, just call
+png_read_rows() seven times to read in all seven images. Each of the
+images is a valid image by itself, or they can all be combined on an
+8x8 grid to form a single image (although if you intend to combine them
+you would be far better off using the libpng interlace handling).
+
+The first pass will return an image 1/8 as wide as the entire image
+(every 8th column starting in column 0) and 1/8 as high as the original
+(every 8th row starting in row 0), the second will be 1/8 as wide
+(starting in column 4) and 1/8 as high (also starting in row 0). The
+third pass will be 1/4 as wide (every 4th pixel starting in column 0) and
+1/8 as high (every 8th row starting in row 4), and the fourth pass will
+be 1/4 as wide and 1/4 as high (every 4th column starting in column 2,
+and every 4th row starting in row 0). The fifth pass will return an
+image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2),
+while the sixth pass will be 1/2 as wide and 1/2 as high as the original
+(starting in column 1 and row 0). The seventh and final pass will be as
+wide as the original, and 1/2 as high, containing all of the odd
+numbered scanlines. Phew!
+
+If you want libpng to expand the images, call this before calling
+png_start_read_image() or png_read_update_info():
+
+ if (interlace_type == PNG_INTERLACE_ADAM7)
+ number_of_passes
+ = png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+This function can be called even if the file is not interlaced,
+where it will return one pass.
+
+If you are not going to display the image after each pass, but are
+going to wait until the entire image is read in, use the sparkle
+effect. This effect is faster and the end result of either method
+is exactly the same. If you are planning on displaying the image
+after each pass, the "rectangle" effect is generally considered the
+better looking one.
+
+If you only want the "sparkle" effect, just call png_read_rows() as
+normal, with the third parameter NULL. Make sure you make pass over
+the image number_of_passes times, and you don't change the data in the
+rows between calls. You can change the locations of the data, just
+not the data. Each pass only writes the pixels appropriate for that
+pass, and assumes the data from previous passes is still valid.
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+If you only want the first effect (the rectangles), do the same as
+before except pass the row buffer in the third parameter, and leave
+the second parameter NULL.
+
+ png_read_rows(png_ptr, NULL, row_pointers,
+ number_of_rows);
+
+After you are finished reading the image, you can finish reading
+the file. If you are interested in comments or time, which may be
+stored either before or after the image data, you should pass the
+separate png_info struct if you want to keep the comments from
+before and after the image separate. If you are not interested, you
+can pass NULL.
+
+ png_read_end(png_ptr, end_info);
+
+When you are done, you can free all memory allocated by libpng like this:
+
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+
+For a more compact example of reading a PNG image, see the file example.c.
+
+
+Reading PNG files progressively:
+
+The progressive reader is slightly different then the non-progressive
+reader. Instead of calling png_read_info(), png_read_rows(), and
+png_read_end(), you make one call to png_process_data(), which calls
+callbacks when it has the info, a row, or the end of the image. You
+set up these callbacks with png_set_progressive_read_fn(). You don't
+have to worry about the input/output functions of libpng, as you are
+giving the library the data directly in png_process_data(). I will
+assume that you have read the section on reading PNG files above,
+so I will only highlight the differences (although I will show
+all of the code).
+
+png_structp png_ptr;
+png_infop info_ptr;
+
+ /* An example code fragment of how you would
+ initialize the progressive reader in your
+ application. */
+ int
+ initialize_png_reader()
+ {
+ png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return -1;
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
+ (png_infopp)NULL);
+ return -1;
+ }
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return -1;
+ }
+
+ /* This one's new. You can provide functions
+ to be called when the header info is valid,
+ when each row is completed, and when the image
+ is finished. If you aren't using all functions,
+ you can specify NULL parameters. Even when all
+ three functions are NULL, you need to call
+ png_set_progressive_read_fn(). You can use
+ any struct as the user_ptr (cast to a void pointer
+ for the function call), and retrieve the pointer
+ from inside the callbacks using the function
+
+ png_get_progressive_ptr(png_ptr);
+
+ which will return a void pointer, which you have
+ to cast appropriately.
+ */
+ png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
+ info_callback, row_callback, end_callback);
+
+ return 0;
+ }
+
+ /* A code fragment that you call as you receive blocks
+ of data */
+ int
+ process_data(png_bytep buffer, png_uint_32 length)
+ {
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return -1;
+ }
+
+ /* This one's new also. Simply give it a chunk
+ of data from the file stream (in order, of
+ course). On machines with segmented memory
+ models machines, don't give it any more than
+ 64K. The library seems to run fine with sizes
+ of 4K. Although you can give it much less if
+ necessary (I assume you can give it chunks of
+ 1 byte, I haven't tried less then 256 bytes
+ yet). When this function returns, you may
+ want to display any rows that were generated
+ in the row callback if you don't already do
+ so there.
+ */
+ png_process_data(png_ptr, info_ptr, buffer, length);
+ return 0;
+ }
+
+ /* This function is called (as set by
+ png_set_progressive_read_fn() above) when enough data
+ has been supplied so all of the header has been
+ read.
+ */
+ void
+ info_callback(png_structp png_ptr, png_infop info)
+ {
+ /* Do any setup here, including setting any of
+ the transformations mentioned in the Reading
+ PNG files section. For now, you _must_ call
+ either png_start_read_image() or
+ png_read_update_info() after all the
+ transformations are set (even if you don't set
+ any). You may start getting rows before
+ png_process_data() returns, so this is your
+ last chance to prepare for that.
+ */
+ }
+
+ /* This function is called when each row of image
+ data is complete */
+ void
+ row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+ {
+ /* If the image is interlaced, and you turned
+ on the interlace handler, this function will
+ be called for every row in every pass. Some
+ of these rows will not be changed from the
+ previous pass. When the row is not changed,
+ the new_row variable will be NULL. The rows
+ and passes are called in order, so you don't
+ really need the row_num and pass, but I'm
+ supplying them because it may make your life
+ easier.
+
+ For the non-NULL rows of interlaced images,
+ you must call png_progressive_combine_row()
+ passing in the row and the old row. You can
+ call this function for NULL rows (it will just
+ return) and for non-interlaced images (it just
+ does the memcpy for you) if it will make the
+ code easier. Thus, you can just do this for
+ all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row,
+ new_row);
+
+ /* where old_row is what was displayed for
+ previously for the row. Note that the first
+ pass (pass == 0, really) will completely cover
+ the old row, so the rows do not have to be
+ initialized. After the first pass (and only
+ for interlaced images), you will have to pass
+ the current row, and the function will combine
+ the old row and the new row.
+ */
+ }
+
+ void
+ end_callback(png_structp png_ptr, png_infop info)
+ {
+ /* This function is called after the whole image
+ has been read, including any chunks after the
+ image (up to and including the IEND). You
+ will usually have the same info chunk as you
+ had in the header, although some data may have
+ been added to the comments and time fields.
+
+ Most people won't do much here, perhaps setting
+ a flag that marks the image as finished.
+ */
+ }
+
+
+
+IV. Writing
+
+Much of this is very similar to reading. However, everything of
+importance is repeated here, so you won't have to constantly look
+back up in the reading section to understand writing.
+
+You will want to do the I/O initialization before you get into libpng,
+so if it doesn't work, you don't have anything to undo. If you are not
+using the standard I/O functions, you will need to replace them with
+custom writing functions. See the discussion under Customizing libpng.
+
+ FILE *fp = fopen(file_name, "wb");
+ if (!fp)
+ {
+ return;
+ }
+
+Next, png_struct and png_info need to be allocated and initialized.
+As these can be both relatively large, you may not want to store these
+on the stack, unless you have stack space to spare. Of course, you
+will want to check if they return NULL. If you are also reading,
+you won't want to name your read structure and your write structure
+both "png_ptr"; you can call them anything you like, such as
+"read_ptr" and "write_ptr". Look at pngtest.c, for example.
+
+ png_structp png_ptr = png_create_write_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return;
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr,
+ (png_infopp)NULL);
+ return;
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_write_struct_2() instead of png_create_read_struct():
+
+ png_structp png_ptr = png_create_write_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+After you have these structures, you will need to set up the
+error handling. When libpng encounters an error, it expects to
+longjmp() back to your routine. Therefore, you will need to call
+setjmp() and pass the png_ptr->jmpbuf. If you
+write the file from different routines, you will need to update
+the jmpbuf field every time you enter a new routine that will
+call a png_ function. See your documentation of setjmp/longjmp
+for your compiler for more information on setjmp/longjmp. See
+the discussion on libpng error handling in the Customizing Libpng
+section below for more information on the libpng error handling.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return;
+ }
+ ...
+ return;
+
+Now you need to set up the output code. The default for libpng is to
+use the C function fwrite(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. Again, if you wish to handle writing data in
+another way, see the discussion on libpng I/O handling in the Customizing
+Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+At this point, you can set up a callback function that will be
+called after each row has been written, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void write_row_callback(png_ptr, png_uint_32 row, int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "write_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_write_status_fn(png_ptr, write_row_callback);
+
+You now have the option of modifying how the compression library will
+run. The following functions are mainly for testing, but may be useful
+in some cases, like if you need to write PNG files extremely fast and
+are willing to give up some compression, or if you want to get the
+maximum possible compression at the expense of slower writing. If you
+have no special needs in this area, let the library do what it wants by
+not calling this function at all, as it has been tuned to deliver a good
+speed/compression ratio. The second parameter to png_set_filter() is
+the filter method, for which the only valid value is '0' (as of the
+October 1996 PNG specification, version 1.0). The third parameter is a
+flag that indicates which filter type(s) are to be tested for each
+scanline. See the Compression Library for details on the specific filter
+types.
+
+
+ /* turn on or off filtering, and/or choose
+ specific filters */
+ png_set_filter(png_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_SUB |
+ PNG_FILTER_PAETH);
+
+The png_set_compression_???() functions interface to the zlib compression
+library, and should mostly be ignored unless you really know what you are
+doing. The only generally useful call is png_set_compression_level()
+which changes how much time zlib spends on trying to compress the image
+data. See the Compression Library for details on the compression levels.
+
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr,
+ Z_BEST_COMPRESSION);
+
+ /* set other zlib parameters */
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_strategy(png_ptr,
+ Z_DEFAULT_STRATEGY);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+
+You now need to fill in the png_info structure with all the data you
+wish to write before the actual image. Note that the only thing you
+are allowed to write after the image is the text chunks and the time
+chunk (as of PNG Specification 1.0, anyway). See png_write_end() and
+the latest PNG specification for more information on that. If you
+wish to write them before the image, fill them in now, and flag that
+data as being valid. If you want to wait until after the data, don't
+fill them until png_write_end(). For all the fields in png_info and
+their data types, see png.h. For explanations of what the fields
+contain, see the PNG specification.
+
+Some of the more important parts of the png_info are:
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ bit_depth, color_type, interlace_type,
+ compression_type, filter_type)
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels.
+ (valid values are 1, 2, 4, 8, 16
+ and depend also on the
+ color_type. See also significant
+ bits (sBIT) below).
+ color_type - describes which color/alpha
+ channels are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ interlace_type - PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7
+ compression_type - (must be
+ PNG_COMPRESSION_TYPE_DEFAULT)
+ filter_type - (must be PNG_FILTER_TYPE_DEFAULT)
+
+ png_set_PLTE(png_ptr, info_ptr, palette,
+ num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ gamma - the gamma the image was created
+ at (PNG_INFO_gAMA)
+
+ png_set_sRGB(png_ptr, info_ptr, srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of
+ the sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This chunk also implies specific
+ values of gAMA and cHRM. Rendering
+ intent is the CSS-1 property that
+ has been defined by the International
+ Color Consortium
+ (http://www.color.org).
+ It can be one of
+ PNG_SRGB_INTENT_SATURATION,
+ PNG_SRGB_INTENT_PERCEPTUAL,
+ PNG_SRGB_INTENT_ABSOLUTE, or
+ PNG_SRGB_INTENT_RELATIVE.
+
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
+ srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of the
+ sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This function also causes gAMA and
+ cHRM chunks with the specific values
+ that are consistent with sRGB to be
+ written.
+
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray, red,
+ green, and blue channels, whichever are
+ appropriate for the given color type
+ (png_color_16)
+
+ png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
+ trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - transparent pixel for non-paletted
+ images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_set_hIST(png_ptr, info_ptr, hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_color_16)
+
+ png_set_tIME(png_ptr, info_ptr, mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_set_bKGD(png_ptr, info_ptr, background);
+ background - background color (PNG_VALID_bKGD)
+
+ png_set_text(png_ptr, info_ptr, text_ptr, num_text);
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i]->key - keyword for comment.
+ text_ptr[i]->text - text comments for current
+ keyword.
+ text_ptr[i]->compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE or
+ PNG_TEXT_COMPRESSION_zTXt
+ num_text - number of comments in text_ptr
+
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y,
+ unit_type);
+ offset_x - positive offset from the left
+ edge of the screen
+ offset_y - positive offset from the top
+ edge of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
+ unit_type);
+ res_x - pixels/unit physical resolution
+ in x direction
+ res_y - pixels/unit physical resolution
+ in y direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+In PNG files, the alpha channel in an image is the level of opacity.
+If your data is supplied as a level of transparency, you can invert the
+alpha channel before you write it, so that 0 is fully transparent and 255
+(in 8-bit or paletted images) or 65535 (in 16-bit images) is fully opaque,
+with
+
+ png_set_invert_alpha(png_ptr);
+
+This must appear here instead of later with the other transformations
+because in the case of paletted images the tRNS chunk data has to
+be inverted before the tRNS chunk is written. If your image is not a
+paletted image, the tRNS data (which in such cases represents a single
+color to be rendered as transparent) won't be changed.
+
+A quick word about text and num_text. text is an array of png_text
+structures. num_text is the number of valid structures in the array.
+If you want, you can use max_text to hold the size of the array, but
+libpng ignores it for writing (it does use it for reading). Each
+png_text structure holds a keyword-text value, and a compression type.
+The compression types have the same valid numbers as the compression
+types of the image data. Currently, the only valid number is zero.
+However, you can store text either compressed or uncompressed, unlike
+images, which always have to be compressed. So if you don't want the
+text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE.
+Until text gets around 1000 bytes, it is not worth compressing it.
+After the text has been written out to the file, the compression type
+is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR,
+so that it isn't written out again at the end (in case you are calling
+png_write_end() with the same struct.
+
+The keywords that are given in the PNG Specification are:
+
+ Title Short (one line) title or
+ caption for image
+ Author Name of image's creator
+ Description Description of image (possibly long)
+ Copyright Copyright notice
+ Creation Time Time of original image creation
+ (usually RFC 1123 format, see below)
+ Software Software used to create the image
+ Disclaimer Legal disclaimer
+ Warning Warning of nature of content
+ Source Device used to create the image
+ Comment Miscellaneous comment; conversion
+ from other image format
+
+The keyword-text pairs work like this. Keywords should be short
+simple descriptions of what the comment is about. Some typical
+keywords are found in the PNG specification, as is some recommendations
+on keywords. You can repeat keywords in a file. You can even write
+some text before the image and some after. For example, you may want
+to put a description of the image before the image, but leave the
+disclaimer until after, so viewers working over modem connections
+don't have to wait for the disclaimer to go over the modem before
+they start seeing the image. Finally, keywords should be full
+words, not abbreviations. Keywords and text are in the ISO 8859-1
+(Latin-1) character set (a superset of regular ASCII) and can not
+contain NUL characters, and should not contain control or other
+unprintable characters. To make the comments widely readable, stick
+with basic ASCII, and avoid machine specific character set extensions
+like the IBM-PC character set. The keyword must be present, but
+you can leave off the text string on non-compressed pairs.
+Compressed pairs must have a text string, as only the text string
+is compressed anyway, so the compression would be meaningless.
+
+PNG supports modification time via the png_time structure. Two
+conversion routines are proved, png_convert_from_time_t() for
+time_t and png_convert_from_struct_tm() for struct tm. The
+time_t routine uses gmtime(). You don't have to use either of
+these, but if you wish to fill in the png_time structure directly,
+you should provide the time in universal time (GMT) if possible
+instead of your local time. Note that the year number is the full
+year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and
+that months start with 1.
+
+If you want to store the time of the original image creation, you should
+use a plain tEXt chunk with the "Creation Time" keyword. This is
+necessary because the "creation time" of a PNG image is somewhat vague,
+depending on whether you mean the PNG file, the time the image was
+created in a non-PNG format, a still photo from which the image was
+scanned, or possibly the subject matter itself. In order to facilitate
+machine-readable dates, it is recommended that the "Creation Time"
+tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"),
+although this isn't a requirement. Unlike the tIME chunk, the
+"Creation Time" tEXt chunk is not expected to be automatically changed
+by the software. To facilitate the use of RFC 1123 dates, a function
+png_convert_to_rfc1123(png_timep) is provided to convert from PNG
+time to an RFC 1123 format string.
+
+You are now ready to write all the file information up to the actual
+image data. You do this with a call to png_write_info().
+
+ png_write_info(png_ptr, info_ptr);
+
+After you've written the file information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code tells
+the library to expand the input data to 4 or 8 bytes per pixel
+(or expand 1 or 2-byte grayscale data to 2 or 4 bytes per pixel).
+
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+where the 0 is the value that will be put in the 4th byte, and the
+location is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending
+upon whether the filler byte is stored XRGB or RGBX.
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit files.
+If the data is supplied at 1 pixel per byte, use this code, which will
+correctly pack the pixels into a single byte:
+
+ png_set_packing(png_ptr);
+
+PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your
+data is of another bit depth, you can write an sBIT chunk into the
+file so that decoders can get the original data if desired.
+
+ /* Set the true bit depth of the image data */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit.red = true_bit_depth;
+ sig_bit.green = true_bit_depth;
+ sig_bit.blue = true_bit_depth;
+ }
+ else
+ {
+ sig_bit.gray = true_bit_depth;
+ }
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ sig_bit.alpha = true_bit_depth;
+ }
+
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+If the data is stored in the row buffer in a bit depth other than
+one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG),
+this will scale the values to appear to be the correct bit depth as
+is required by PNG.
+
+ png_set_shift(png_ptr, &sig_bit);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code would be used if they are
+supplied the other way (little-endian, i.e. least significant bits
+first, the way PCs store them):
+
+ if (bit_depth > 8)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. This code
+would be used if they are supplied as blue, green, red:
+
+ png_set_bgr(png_ptr);
+
+PNG files describe monochrome as black being zero and white being
+one. This code would be used if the pixels are supplied with this reversed
+(black being one and white being zero):
+
+ png_set_invert_mono(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_write_user_transform_fn(png_ptr,
+ write_transform_fn);
+
+You must supply the function
+
+ void write_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+before any of the other transformations have been processed.
+
+It is possible to have libpng flush any pending output, either manually,
+or automatically after a certain number of lines have been written. To
+flush the output stream a single time call:
+
+ png_write_flush(png_ptr);
+
+and to have libpng flush the output stream periodically after a certain
+number of scanlines have been written, call:
+
+ png_set_flush(png_ptr, nrows);
+
+Note that the distance between rows is from the last time png_write_flush()
+was called, or the first row of the image if it has never been called.
+So if you write 50 lines, and then png_set_flush 25, it will flush the
+output on the next scanline, and every 25 lines thereafter, unless
+png_write_flush() is called before 25 more lines have been written.
+If nrows is too small (less than about 10 lines for a 640 pixel wide
+RGB image) the image compression may decrease noticeably (although this
+may be acceptable for real-time applications). Infrequent flushing will
+only degrade the compression performance by a few percent over images
+that do not use flushing.
+
+That's it for the transformations. Now you can write the image data.
+The simplest way to do this is in one function call. If have the
+whole image in memory, you can just call png_write_image() and libpng
+will write the image. You will need to pass in an array of pointers to
+each row. This function automatically handles interlacing, so you don't
+need to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_write_rows().
+
+ png_write_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_byte *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to write the whole image at once, you can
+use png_write_rows() instead. If the file is not interlaced,
+this is simple:
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+row_pointers is the same as in the png_write_image() call.
+
+If you are just writing one row at a time, you can do this with
+row_pointers:
+
+ png_bytep row_pointer = row;
+
+ png_write_row(png_ptr, &row_pointer);
+
+When the file is interlaced, things can get a good deal more
+complicated. The only currently (as of February 1998 -- PNG Specification
+version 1.0, dated October 1996) defined interlacing scheme for PNG files
+is the "Adam7" interlace scheme, that breaks down an
+image into seven smaller images of varying size. libpng will build
+these images for you, or you can do them yourself. If you want to
+build them yourself, see the PNG specification for details of which
+pixels to write when.
+
+If you don't want libpng to handle the interlacing details, just
+use png_set_interlace_handling() and call png_write_rows() the
+correct number of times to write all seven sub-images.
+
+If you want libpng to build the sub-images, call this before you start
+writing any rows:
+
+ number_of_passes =
+ png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+
+Then write the complete image number_of_passes times.
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+As some of these rows are not used, and thus return immediately,
+you may want to read about interlacing in the PNG specification,
+and only update the rows that are actually used.
+
+After you are finished writing the image, you should finish writing
+the file. If you are interested in writing comments or time, you should
+pass an appropriately filled png_info pointer. If you are not interested,
+you can pass NULL.
+
+ png_write_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+You must free any data you allocated for info_ptr, such as comments,
+palette, or histogram, before the call to png_destroy_write_struct();
+
+For a more compact example of writing a PNG image, see the file example.c.
+
+
+V. Modifying/Customizing libpng:
+
+There are two issues here. The first is changing how libpng does
+standard things like memory allocation, input/output, and error handling.
+The second deals with more complicated things like adding new chunks,
+adding new transformations, and generally changing how libpng works.
+
+All of the memory allocation, input/output, and error handling in libpng
+goes through callbacks that are user settable. The default routines are
+in pngmem.c, pngrio.c, pngwio.c, and pngerror.c respectively. To change
+these functions, call the appropriate png_set_???_fn() function.
+
+Memory allocation is done through the functions png_large_malloc(),
+png_malloc(), png_realloc(), png_large_free(), and png_free(). These
+currently just call the standard C functions. The large functions must
+handle exactly 64K, but they don't have to handle more than that. If
+your pointers can't access more then 64K at a time, you will want to set
+MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling
+memory allocation on a platform will change between applications, these
+functions must be modified in the library at compile time.
+
+Input/Output in libpng is done through png_read() and png_write(),
+which currently just call fread() and fwrite(). The FILE * is stored in
+png_struct and is initialized via png_init_io(). If you wish to change
+the method of I/O, the library supplies callbacks that you can set
+through the function png_set_read_fn() and png_set_write_fn() at run
+time, instead of calling the png_init_io() function. These functions
+also provide a void pointer that can be retrieved via the function
+png_get_io_ptr(). For example:
+
+ png_set_read_fn(png_structp read_ptr,
+ voidp read_io_ptr, png_rw_ptr read_data_fn)
+
+ png_set_write_fn(png_structp write_ptr,
+ voidp write_io_ptr, png_rw_ptr write_data_fn,
+ png_flush_ptr output_flush_fn);
+
+ voidp read_io_ptr = png_get_io_ptr(read_ptr);
+ voidp write_io_ptr = png_get_io_ptr(write_ptr);
+
+The replacement I/O functions should have prototypes as follows:
+
+ void user_read_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_write_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_flush_data(png_structp png_ptr);
+
+Supplying NULL for the read, write, or flush functions sets them back
+to using the default C stream functions. It is an error to read from
+a write stream, and vice versa.
+
+Error handling in libpng is done through png_error() and png_warning().
+Errors handled through png_error() are fatal, meaning that png_error()
+should never return to its caller. Currently, this is handled via
+setjmp() and longjmp(), but you could change this to do things like
+exit() if you should wish. On non-fatal errors, png_warning() is called
+to print a warning message, and then control returns to the calling code.
+By default png_error() and png_warning() print a message on stderr via
+fprintf() unless the library is compiled with PNG_NO_STDIO defined. If
+you wish to change the behavior of the error functions, you will need to
+set up your own message callbacks. These functions are normally supplied
+at the time that the png_struct is created. It is also possible to change
+these functions after png_create_???_struct() has been called by calling:
+
+ png_set_error_fn(png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warning_fn);
+
+ png_voidp error_ptr = png_get_error_ptr(png_ptr);
+
+If NULL is supplied for either error_fn or warning_fn, then the libpng
+default function will be used, calling fprintf() and/or longjmp() if a
+problem is encountered. The replacement error functions should have
+parameters as follows:
+
+ void user_error_fn(png_structp png_ptr,
+ png_const_charp error_msg);
+ void user_warning_fn(png_structp png_ptr,
+ png_const_charp warning_msg);
+
+The motivation behind using setjmp() and longjmp() is the C++ throw and
+catch exception handling methods. This makes the code much easier to write,
+as there is no need to check every return code of every function call.
+However, there are some uncertainties about the status of local variables
+after a longjmp, so the user may want to be careful about doing anything after
+setjmp returns non-zero besides returning itself. Consult your compiler
+documentation for more details.
+
+If you need to read or write custom chunks, you will need to get deeper
+into the libpng code, as a mechanism has not yet been supplied for user
+callbacks with custom chunks. First, read the PNG specification, and have
+a first level of understanding of how it works. Pay particular attention
+to the sections that describe chunk names, and look at how other chunks
+were designed, so you can do things similarly. Second, check out the
+sections of libpng that read and write chunks. Try to find a chunk that
+is similar to yours and copy off of it. More details can be found in the
+comments inside the code. A way of handling unknown chunks in a generic
+method, potentially via callback functions, would be best.
+
+If you wish to write your own transformation for the data, look through
+the part of the code that does the transformations, and check out some of
+the simpler ones to get an idea of how they work. Try to find a similar
+transformation to the one you want to add and copy off of it. More details
+can be found in the comments inside the code itself.
+
+Configuring for 16 bit platforms:
+
+You may need to change the png_large_malloc() and png_large_free()
+routines in pngmem.c, as these are required to allocate 64K, although
+there is already support for many of the common DOS compilers. Also,
+you will want to look into zconf.h to tell zlib (and thus libpng) that
+it cannot allocate more then 64K at a time. Even if you can, the memory
+won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K.
+
+Configuring for DOS:
+
+For DOS users who only have access to the lower 640K, you will
+have to limit zlib's memory usage via a png_set_compression_mem_level()
+call. See zlib.h or zconf.h in the zlib library for more information.
+
+Configuring for Medium Model:
+
+Libpng's support for medium model has been tested on most of the popular
+compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets
+defined, and FAR gets defined to far in pngconf.h, and you should be
+all set. Everything in the library (except for zlib's structure) is
+expecting far data. You must use the typedefs with the p or pp on
+the end for pointers (or at least look at them and be careful). Make
+note that the row's of data are defined as png_bytepp, which is an
+unsigned char far * far *.
+
+Configuring for gui/windowing platforms:
+
+You will need to write new error and warning functions that use the GUI
+interface, as described previously, and set them to be the error and
+warning functions at the time that png_create_???_struct() is called,
+in order to have them available during the structure initialization.
+They can be changed later via png_set_error_fn(). On some compilers,
+you may also have to change the memory allocators (png_malloc, etc.).
+
+Configuring for compiler xxx:
+
+All includes for libpng are in pngconf.h. If you need to add/change/delete
+an include, this is the place to do it. The includes that are not
+needed outside libpng are protected by the PNG_INTERNAL definition,
+which is only defined for those routines inside libpng itself. The
+files in libpng proper only include png.h, which includes pngconf.h.
+
+Configuring zlib:
+
+There are special functions to configure the compression. Perhaps the
+most useful one changes the compression level, which currently uses
+input compression values in the range 0 - 9. The library normally
+uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests
+have shown that for a large majority of images, compression values in
+the range 3-6 compress nearly as well as higher levels, and do so much
+faster. For online applications it may be desirable to have maximum speed
+(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also
+specify no compression (Z_NO_COMPRESSION = 0), but this would create
+files larger than just storing the raw bitmap. You can specify the
+compression level by calling:
+
+ png_set_compression_level(png_ptr, level);
+
+Another useful one is to reduce the memory level used by the library.
+The memory level defaults to 8, but it can be lowered if you are
+short on memory (running DOS, for example, where you only have 640K).
+
+ png_set_compression_mem_level(png_ptr, level);
+
+The other functions are for configuring zlib. They are not recommended
+for normal use and may result in writing an invalid PNG file. See
+zlib.h for more information on what these mean.
+
+ png_set_compression_strategy(png_ptr,
+ strategy);
+ png_set_compression_window_bits(png_ptr,
+ window_bits);
+ png_set_compression_method(png_ptr, method);
+
+Controlling row filtering:
+
+If you want to control whether libpng uses filtering or not, which
+filters are used, and how it goes about picking row filters, you
+can call one of these functions. The selection and configuration
+of row filters can have a significant impact on the size and
+encoding speed and a somewhat lesser impact on the decoding speed
+of an image. Filtering is enabled by default for RGB and grayscale
+images (with and without alpha), but not for paletted images nor
+for any images with bit depths less than 8 bits/pixel.
+
+The 'method' parameter sets the main filtering method, which is
+currently only '0' in the PNG 1.0 specification. The 'filters'
+parameter sets which filter(s), if any, should be used for each
+scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS
+to turn filtering on and off, respectively.
+
+Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB,
+PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise
+ORed together '|' to specify one or more filters to use. These
+filters are described in more detail in the PNG specification. If
+you intend to change the filter type during the course of writing
+the image, you should start with flags set for all of the filters
+you intend to use so that libpng can initialize its internal
+structures appropriately for all of the filter types.
+
+ filters = PNG_FILTER_NONE | PNG_FILTER_SUB
+ | PNG_FILTER_UP;
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
+ filters);
+
+It is also possible to influence how libpng chooses from among the
+available filters. This is done in two ways - by telling it how
+important it is to keep the same filter for successive rows, and
+by telling it the relative computational costs of the filters.
+
+ double weights[3] = {1.5, 1.3, 1.1},
+ costs[PNG_FILTER_VALUE_LAST] =
+ {1.0, 1.3, 1.3, 1.5, 1.7};
+
+ png_set_filter_selection(png_ptr,
+ PNG_FILTER_SELECTION_WEIGHTED, 3,
+ weights, costs);
+
+The weights are multiplying factors that indicate to libpng that the
+row filter should be the same for successive rows unless another row filter
+is that many times better than the previous filter. In the above example,
+if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a
+"sum of absolute differences" 1.5 x 1.3 times higher than other filters
+and still be chosen, while the NONE filter could have a sum 1.1 times
+higher than other filters and still be chosen. Unspecified weights are
+taken to be 1.0, and the specified weights should probably be declining
+like those above in order to emphasize recent filters over older filters.
+
+The filter costs specify for each filter type a relative decoding cost
+to be considered when selecting row filters. This means that filters
+with higher costs are less likely to be chosen over filters with lower
+costs, unless their "sum of absolute differences" is that much smaller.
+The costs do not necessarily reflect the exact computational speeds of
+the various filters, since this would unduly influence the final image
+size.
+
+Note that the numbers above were invented purely for this example and
+are given only to help explain the function usage. Little testing has
+been done to find optimum values for either the costs or the weights.
+
+Removing unwanted object code:
+
+There are a bunch of #define's in pngconf.h that control what parts of
+libpng are compiled. All the defines end in _SUPPORTED. If you are
+never going to use a capability, you can change the #define to #undef
+before recompiling libpng and save yourself code and data space, or
+you can turn off individual capabilities with defines that begin with
+PNG_NO_.
+
+You can also turn all of the transforms and ancillary chunk capabilities
+off en masse with compiler directives that define
+PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS,
+or all four,
+along with directives to turn on any of the capabilities that you do
+want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable
+the extra transformations but still leave the library fully capable of reading
+and writing PNG files with all known public chunks [except for sPLT].
+Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive
+produces a library that is incapable of reading or writing ancillary chunks.
+If you are not using the progressive reading capability, you can
+turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse
+this with the INTERLACING capability, which you'll still have).
+
+All the reading and writing specific code are in separate files, so the
+linker should only grab the files it needs. However, if you want to
+make sure, or if you are building a stand alone library, all the
+reading files start with pngr and all the writing files start with
+pngw. The files that don't match either (like png.c, pngtrans.c, etc.)
+are used for both reading and writing, and always need to be included.
+The progressive reader is in pngpread.c
+
+If you are creating or distributing a dynamically linked library (a .so
+or DLL file), you should not remove or disable any parts of the library,
+as this will cause applications linked with different versions of the
+library to fail if they call functions not available in your library.
+The size of the library itself should not be an issue, because only
+those sections that are actually used will be loaded into memory.
+
+Requesting debug printout:
+
+The macro definition PNG_DEBUG can be used to request debugging
+printout. Set it to an integer value in the range 0 to 3. Higher
+numbers result in increasing amounts of debugging information. The
+information is printed to the "stderr" file, unless another file
+name is specified in the PNG_DEBUG_FILE macro definition.
+
+When PNG_DEBUG > 0, the following functions (macros) become available:
+
+ png_debug(level, message)
+ png_debug1(level, message, p1)
+ png_debug2(level, message, p1, p2)
+
+in which "level" is compared to PNG_DEBUG to decide whether to print
+the message, "message" is the formatted string to be printed,
+and p1 and p2 are parameters that are to be embedded in the string
+according to printf-style formatting directives. For example,
+
+ png_debug1(2, "foo=%d\n", foo);
+
+is expanded to
+
+ if(PNG_DEBUG > 2)
+ fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo);
+
+When PNG_DEBUG is defined but is zero, the macros aren't defined, but you
+can still use PNG_DEBUG to control your own debugging:
+
+ #ifdef PNG_DEBUG
+ fprintf(stderr, ...
+ #endif
+
+When PNG_DEBUG = 1, the macros are defined, but only png_debug statements
+having level = 0 will be printed. There aren't any such statements in
+this version of libpng, but if you insert some they will be printed.
+
+VI. Changes to Libpng from version 0.88
+
+It should be noted that versions of libpng later than 0.96 are not
+distributed by the original libpng author, Guy Schalnat, nor by
+Andreas Dilger, who had taken over from Guy during 1996 and 1997, and
+distributed versions 0.89 through 0.96, but rather by another member
+of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are
+still alive and well, but they have moved on to other things.
+
+The old libpng functions png_read_init(), png_write_init(),
+png_info_init(), png_read_destroy(), and png_write_destory() have been
+moved to PNG_INTERNAL in version 0.95 to discourage their use. The
+preferred method of creating and initializing the libpng structures is
+via the png_create_read_struct(), png_create_write_struct(), and
+png_create_info_struct() because they isolate the size of the structures
+from the application, allow version error checking, and also allow the
+use of custom error handling routines during the initialization, which
+the old functions do not. The functions png_read_destroy() and
+png_write_destroy() do not actually free the memory that libpng
+allocated for these structs, but just reset the data structures, so they
+can be used instead of png_destroy_read_struct() and
+png_destroy_write_struct() if you feel there is too much system overhead
+allocating and freeing the png_struct for each image read.
+
+Setting the error callbacks via png_set_message_fn() before
+png_read_init() as was suggested in libpng-0.88 is no longer supported
+because this caused applications that do not use custom error functions
+to fail if the png_ptr was not initialized to zero. It is still possible
+to set the error callbacks AFTER png_read_init(), or to change them with
+png_set_error_fn(), which is essentially the same function, but with a
+new name to force compilation errors with applications that try to use
+the old method.
+
+VII. Y2K Compliance in libpng
+
+January 13, 1999
+
+Since the PNG Development group is an ad-hoc body, we can't make
+an official declaration.
+
+This is your unofficial assurance that libpng from version 0.81 and
+upward are Y2K compliant. It is my belief that earlier versions were
+also Y2K compliant.
+
+Libpng only has three year fields. One is a 2-byte unsigned integer that
+will hold years up to 65535. The other two hold the date in text
+format, and will hold years up to 9999.
+
+The integer is
+ "png_uint_16 year" in png_time_struct.
+
+The strings are
+ "png_charp time_buffer" in png_struct and
+ "near_time_buffer", which is a local character string in png.c.
+
+There are seven time-related functions:
+
+ png_convert_to_rfc_1123() in png.c
+ (formerly png_convert_to_rfc_1152() in error)
+ png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ png_convert_from_time_t() in pngwrite.c
+ png_get_tIME() in pngget.c
+ png_handle_tIME() in pngrutil.c, called in pngread.c
+ png_set_tIME() in pngset.c
+ png_write_tIME() in pngwutil.c, called in pngwrite.c
+
+All appear to handle dates properly in a Y2K environment. The
+png_convert_from_time_t() function calls gmtime() to convert from system
+clock time, which returns (year - 1900), which we properly convert to
+the full 4-digit year. There is a possibility that applications using
+libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+function, or incorrectly passing only a 2-digit year instead of
+"year - 1900" into the png_convert_from_struct_tm() function, but this
+is not under our control. The libpng documentation has always stated
+that it works with 4-digit years, and the APIs have been documented as
+such.
+
+The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+integer to hold the year, and can hold years as large as 65535.
+
+
+ Glenn Randers-Pehrson
+ libpng maintainer
+ PNG Development Group
--- /dev/null
+.TH LIBPNGPF 3 "January 14, 1999"
+.SH NAME
+libpng \- Portable Network Graphics (PNG) Reference Library 1.0.3 - January 14, 1999
+(private functions)
+.SH SYNOPSIS
+#include <png.h>
+
+void png_build_gamma_table (png_structp png_ptr);
+
+void png_build_grayscale_palette (int bit_depth, png_colorp
+palette);
+
+void png_calculate_crc (png_structp png_ptr, png_bytep ptr,
+png_size_t length);
+void png_check_chunk_name (png_structp png_ptr, png_bytep
+chunk_name);
+
+png_size_t png_check_keyword (png_structp png_ptr, png_charp
+key, png_charpp new_key);
+
+void png_combine_row (png_structp png_ptr, png_bytep row, int
+mask);
+
+void png_correct_palette (png_structp png_ptr, png_colorp
+palette, int num_palette);
+
+int png_crc_error (png_structp png_ptr);
+
+int png_crc_finish (png_structp png_ptr, png_uint_32 skip);
+
+void png_crc_read (png_structp png_ptr, png_bytep buf,
+png_size_t length);
+
+png_voidp png_create_struct (int type, png_malloc_ptr malloc_fn);
+
+png_voidp png_create_struct_2 (int type);
+
+void png_destroy_struct (png_voidp struct_ptr);
+
+void png_destroy_struct_2 (png_voidp struct_ptr, png_free_ptr
+free_fn);
+
+void png_do_background (png_row_infop row_info, png_bytep row,
+png_color_16p trans_values, png_color_16p background,
+png_color_16p background_1, png_bytep gamma_table, png_bytep
+gamma_from_1, png_bytep gamma_to_1, png_uint_16pp gamma_16,
+png_uint_16pp gamma_16_from_1, png_uint_16pp gamma_16_to_1, int
+gamma_shift);
+
+void png_do_bgr (png_row_infop row_info, png_bytep row);
+
+void png_do_chop (png_row_infop row_info, png_bytep row);
+
+void png_do_dither (png_row_infop row_info, png_bytep row,
+png_bytep palette_lookup, png_bytep dither_lookup);
+
+void png_do_expand (png_row_infop row_info, png_bytep row,
+png_color_16p trans_value);
+
+void png_do_expand_palette (png_row_infop row_info, png_bytep
+row, png_colorp palette, png_bytep trans, int num_trans);
+
+void png_do_gamma (png_row_infop row_info, png_bytep row,
+png_bytep gamma_table, png_uint_16pp gamma_16_table, int
+gamma_shift);
+
+void png_do_gray_to_rgb (png_row_infop row_info, png_bytep
+row);
+
+void png_do_invert (png_row_infop row_info, png_bytep row);
+
+void png_do_pack (png_row_infop row_info, png_bytep row,
+png_uint_32 bit_depth);
+
+void png_do_packswap (png_row_infop row_info, png_bytep row);
+
+void png_do_read_filler (png_row_infop row_info, png_bytep row,
+png_uint_32 filler, png_uint_32 flags);
+
+void png_do_read_interlace (png_row_infop row_info, png_bytep
+row, int pass, png_uint_32 transformations);
+
+void png_do_read_invert_alpha (png_row_infop row_info,
+png_bytep row);
+
+void png_do_read_swap_alpha (png_row_infop row_info, png_bytep
+row);
+
+void png_do_read_transformations (png_structp png_ptr);
+
+int png_do_rgb_to_gray (png_row_infop row_info, png_bytep
+row);
+
+void png_do_shift (png_row_infop row_info, png_bytep row,
+png_color_8p bit_depth);
+
+void png_do_strip_filler (png_row_infop row_info, png_bytep
+row, png_uint_32 flags);
+
+void png_do_swap (png_row_infop row_info, png_bytep row);
+
+void png_do_unpack (png_row_infop row_info, png_bytep row);
+
+void png_do_unshift (png_row_infop row_info, png_bytep row,
+png_color_8p sig_bits);
+
+void png_do_write_interlace (png_row_infop row_info, png_bytep
+row, int pass);
+
+void png_do_write_invert_alpha (png_row_infop row_info,
+png_bytep row);
+
+void png_do_write_swap_alpha (png_row_infop row_info, png_bytep
+row);
+
+void png_do_write_transformations (png_structp png_ptr);
+
+void *png_far_to_near (png_structp png_ptr,png_voidp ptr,
+int check);
+
+void png_flush (png_structp png_ptr);
+
+png_int_32 png_get_int_32 (png_bytep buf);
+
+png_uint_16 png_get_uint_16 (png_bytep buf);
+
+png_uint_32 png_get_uint_32 (png_bytep buf);
+
+void png_handle_bKGD (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_cHRM (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_gAMA (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_hIST (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_IEND (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_IHDR (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_oFFs (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_pCAL (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_pHYs (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_PLTE (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_sBIT (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_sRGB (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_tEXt (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_tIME (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_tRNS (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_handle_unknown (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 length);
+
+void png_handle_zTXt (png_structp png_ptr, png_infop info_ptr,
+png_uint_32 length);
+
+void png_info_destroy (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_init_read_transformations (png_structp png_ptr);
+
+void png_process_IDAT_data (png_structp png_ptr, png_bytep
+buffer, png_size_t buffer_length);
+
+void png_process_some_data (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_check_crc (png_structp png_ptr);
+
+void png_push_crc_finish (png_structp png_ptr);
+
+void png_push_crc_skip (png_structp png_ptr, png_uint_32
+length);
+
+void png_push_fill_buffer (png_structp png_ptr, png_bytep
+buffer, png_size_t length);
+
+void png_push_handle_tEXt (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 length);
+
+void png_push_handle_unknown (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 length);
+
+void png_push_handle_zTXt (png_structp png_ptr, png_infop
+info_ptr, png_uint_32 length);
+
+void png_push_have_end (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_have_info (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_have_row (png_structp png_ptr, png_bytep row);
+
+void png_push_process_row (png_structp png_ptr);
+
+void png_push_read_chunk (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_read_end (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_read_IDAT (png_structp png_ptr);
+
+void png_push_read_sig (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_read_tEXt (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_read_zTXt (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_push_restore_buffer (png_structp png_ptr, png_bytep
+buffer, png_size_t buffer_length);
+
+void png_push_save_buffer (png_structp png_ptr);
+
+void png_read_data (png_structp png_ptr, png_bytep data,
+png_size_t length);
+
+void png_read_filter_row (png_structp png_ptr, png_row_infop
+row_info, png_bytep row, png_bytep prev_row, int filter);
+
+void png_read_finish_row (png_structp png_ptr);
+
+void png_read_init (png_structp png_ptr);
+
+void png_read_push_finish_row (png_structp png_ptr);
+
+void png_read_start_row (png_structp png_ptr);
+
+void png_read_transform_info (png_structp png_ptr, png_infop
+info_ptr);
+
+void png_reset_crc (png_structp png_ptr);
+
+void png_save_int_32 (png_bytep buf, png_int_32 i);
+
+void png_save_uint_16 (png_bytep buf, unsigned int i);
+
+void png_save_uint_32 (png_bytep buf, png_uint_32 i);
+
+void png_write_bKGD (png_structp png_ptr, png_color_16p values,
+int color_type);
+
+void png_write_cHRM (png_structp png_ptr, double white_x,
+double white_y, double red_x, double red_y, double green_x,
+double green_y, double blue_x, double blue_y);
+
+void png_write_data (png_structp png_ptr, png_bytep data,
+png_size_t length);
+void png_write_filtered_row (png_structp png_ptr, png_bytep
+filtered_row);
+
+void png_write_find_filter (png_structp png_ptr, png_row_infop
+row_info);
+
+void png_write_finish_row (png_structp png_ptr);
+
+void png_write_gAMA (png_structp png_ptr, double file_gamma);
+
+void png_write_hIST (png_structp png_ptr, png_uint_16p hist,
+int num_hist);
+
+void png_write_init (png_structp png_ptr);
+
+void png_write_IDAT (png_structp png_ptr, png_bytep data,
+png_size_t length);
+
+void png_write_IEND (png_structp png_ptr);
+
+void png_write_IHDR (png_structp png_ptr, png_uint_32 width,
+png_uint_32 height, int bit_depth, int color_type, int
+compression_type, int filter_type, int interlace_type);
+
+void png_write_oFFs (png_structp png_ptr, png_uint_32 x_offset,
+png_uint_32 y_offset, int unit_type);
+
+void png_write_pCAL (png_structp png_ptr, png_charp purpose,
+png_int_32 X0, png_int_32 X1, int type, int nparams, png_charp
+units, png_charpp params);
+
+void png_write_pHYs (png_structp png_ptr, png_uint_32
+x_pixels_per_unit, png_uint_32 y_pixels_per_unit, int
+unit_type);
+
+void png_write_PLTE (png_structp png_ptr, png_colorp palette,
+png_uint_32 num_pal);
+
+void png_write_sBIT (png_structp png_ptr, png_color_8p sbit,
+int color_type);
+
+void png_write_sig (png_structp png_ptr);
+
+void png_write_sRGB (png_structp png_ptr, int intent);
+
+void png_write_start_row (png_structp png_ptr);
+
+void png_write_tEXt (png_structp png_ptr, png_charp key,
+png_charp text, png_size_t text_len);
+
+void png_write_tIME (png_structp png_ptr, png_timep mod_time);
+
+void png_write_tRNS (png_structp png_ptr, png_bytep trans,
+png_color_16p values, int number, int color_type);
+
+void png_write_zTXt (png_structp png_ptr, png_charp key,
+png_charp text, png_size_t text_len, int compression);
+
+voidpf png_zalloc (voidpf png_ptr, uInt items, uInt size);
+
+void png_zfree (voidpf png_ptr, voidpf ptr);
+
+.SH DESCRIPTION
+The functions listed above are used privately by libpng
+and are not recommended for use by applications. They
+are listed alphabetically here as an aid to libpng maintainers.
+See png.h for more information on these functions.
+
+.SH SEE ALSO
+libpng(3), png(5)
+.SH AUTHOR
+Glenn Randers-Pehrson
--- /dev/null
+.TH PNG 5 "January 14, 1999"
+.SH NAME
+png \- Portable Network Graphics (PNG) format
+.SH DESCRIPTION
+PNG (Portable Network Graphics) is an extensible file format for the
+lossless, portable, well-compressed storage of raster images. PNG provides
+a patent-free replacement for GIF and can also replace many
+common uses of TIFF. Indexed-color, grayscale, and truecolor images are
+supported, plus an optional alpha channel. Sample depths range from
+1 to 16 bits.
+.br
+
+PNG is designed to work well in online viewing applications, such as the
+World Wide Web, so it is fully streamable with a progressive display
+option. PNG is robust, providing both full file integrity checking and
+fast, simple detection of common transmission errors. Also, PNG can store
+gamma and chromaticity data for improved color matching on heterogeneous
+platforms.
+
+.SH "SEE ALSO"
+.IR libpng(3), zlib(3), deflate(5), and zlib(5)
+.LP
+PNG specification:
+RFC 2083
+.IP
+.br
+ftp://ds.internic.net/rfc/rfc2083.txt
+.br
+or (as a W3C Recommendation) at
+.br
+http://www.w3.org/TR/REC-png.html
+.SH AUTHORS
+This man page: Glenn Randers-Pehrson
+.LP
+Portable Network Graphics (PNG) Specification Version 1.0 (October 1, 1996):
+Thomas Boutell and others (png-list@dworkin.wustl.edu).
+.LP
+
+.SH COPYRIGHT NOTICE
+The PNG specification is copyright (c) 1996 Massachussets Institute of
+Technology. See the specification for conditions of use and distribution.
+.LP
+.\" end of man page
+
--- /dev/null
+
+/* png.c - location for general purpose libpng functions
+ *
+ * libpng version 1.0.3 - January 14, 1999
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ */
+
+#define PNG_INTERNAL
+#define PNG_NO_EXTERN
+#include "png.h"
+
+/* Version information for C files. This had better match the version
+ * string defined in png.h.
+ */
+
+char png_libpng_ver[12] = "1.0.3";
+
+/* Place to hold the signature string for a PNG file. */
+png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+
+/* Constant strings for known chunk types. If you need to add a chunk,
+ * add a string holding the name here. If you want to make the code
+ * portable to EBCDIC machines, use ASCII numbers, not characters.
+ */
+png_byte FARDATA png_IHDR[5] = { 73, 72, 68, 82, '\0'};
+png_byte FARDATA png_IDAT[5] = { 73, 68, 65, 84, '\0'};
+png_byte FARDATA png_IEND[5] = { 73, 69, 78, 68, '\0'};
+png_byte FARDATA png_PLTE[5] = { 80, 76, 84, 69, '\0'};
+png_byte FARDATA png_bKGD[5] = { 98, 75, 71, 68, '\0'};
+png_byte FARDATA png_cHRM[5] = { 99, 72, 82, 77, '\0'};
+png_byte FARDATA png_gAMA[5] = {103, 65, 77, 65, '\0'};
+png_byte FARDATA png_hIST[5] = {104, 73, 83, 84, '\0'};
+png_byte FARDATA png_oFFs[5] = {111, 70, 70, 115, '\0'};
+png_byte FARDATA png_pCAL[5] = {112, 67, 65, 76, '\0'};
+png_byte FARDATA png_pHYs[5] = {112, 72, 89, 115, '\0'};
+png_byte FARDATA png_sBIT[5] = {115, 66, 73, 84, '\0'};
+png_byte FARDATA png_sRGB[5] = {115, 82, 71, 66, '\0'};
+png_byte FARDATA png_tEXt[5] = {116, 69, 88, 116, '\0'};
+png_byte FARDATA png_tIME[5] = {116, 73, 77, 69, '\0'};
+png_byte FARDATA png_tRNS[5] = {116, 82, 78, 83, '\0'};
+png_byte FARDATA png_zTXt[5] = {122, 84, 88, 116, '\0'};
+
+/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+/* start of interlace block */
+int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+/* offset to next interlace block */
+int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+/* start of interlace block in the y direction */
+int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+/* offset to next interlace block in the y direction */
+int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+/* Width of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1};
+*/
+
+/* Height of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
+*/
+
+/* Mask to determine which pixels are valid in a pass */
+int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
+
+/* Mask to determine which pixels to overwrite while displaying */
+int FARDATA png_pass_dsp_mask[] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+
+
+/* Tells libpng that we have already handled the first "num_bytes" bytes
+ * of the PNG file signature. If the PNG data is embedded into another
+ * stream we can set num_bytes = 8 so that libpng will not attempt to read
+ * or write any of the magic bytes before it starts on the IHDR.
+ */
+void
+png_set_sig_bytes(png_structp png_ptr, int num_bytes)
+{
+ png_debug(1, "in png_set_sig_bytes\n");
+ if (num_bytes > 8)
+ png_error(png_ptr, "Too many bytes for PNG signature.");
+
+ png_ptr->sig_bytes = num_bytes < 0 ? 0 : num_bytes;
+}
+
+/* Checks whether the supplied bytes match the PNG signature. We allow
+ * checking less than the full 8-byte signature so that those apps that
+ * already read the first few bytes of a file to determine the file type
+ * can simply check the remaining bytes for extra assurance. Returns
+ * an integer less than, equal to, or greater than zero if sig is found,
+ * respectively, to be less than, to match, or be greater than the correct
+ * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
+ */
+int
+png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check)
+{
+ if (num_to_check > 8)
+ num_to_check = 8;
+ else if (num_to_check < 1)
+ return (0);
+
+ if (start > 7)
+ return (0);
+
+ if (start + num_to_check > 8)
+ num_to_check = 8 - start;
+
+ return ((int)(png_memcmp(&sig[start], &png_sig[start], num_to_check)));
+}
+
+/* (Obsolete) function to check signature bytes. It does not allow one
+ * to check a partial signature. This function might be removed in the
+ * future - use png_sig_cmp(). Returns true (nonzero) if the file is a PNG.
+ */
+int
+png_check_sig(png_bytep sig, int num)
+{
+ return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num));
+}
+
+/* Function to allocate memory for zlib. */
+voidpf
+png_zalloc(voidpf png_ptr, uInt items, uInt size)
+{
+ png_uint_32 num_bytes = (png_uint_32)items * size;
+ png_voidp ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
+
+ if (num_bytes > (png_uint_32)0x8000L)
+ {
+ png_memset(ptr, 0, (png_size_t)0x8000L);
+ png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0,
+ (png_size_t)(num_bytes - (png_uint_32)0x8000L));
+ }
+ else
+ {
+ png_memset(ptr, 0, (png_size_t)num_bytes);
+ }
+ return ((voidpf)ptr);
+}
+
+/* function to free memory for zlib */
+void
+png_zfree(voidpf png_ptr, voidpf ptr)
+{
+ png_free((png_structp)png_ptr, (png_voidp)ptr);
+}
+
+/* Reset the CRC variable to 32 bits of 1's. Care must be taken
+ * in case CRC is > 32 bits to leave the top bits 0.
+ */
+void
+png_reset_crc(png_structp png_ptr)
+{
+ png_ptr->crc = crc32(0, Z_NULL, 0);
+}
+
+/* Calculate the CRC over a section of data. We can only pass as
+ * much data to this routine as the largest single buffer size. We
+ * also check that this data will actually be used before going to the
+ * trouble of calculating it.
+ */
+void
+png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
+{
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ if (need_crc)
+ png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
+}
+
+/* Allocate the memory for an info_struct for the application. We don't
+ * really need the png_ptr, but it could potentially be useful in the
+ * future. This should be used in favour of malloc(sizeof(png_info))
+ * and png_info_init() so that applications that want to use a shared
+ * libpng don't have to be recompiled if png_info changes size.
+ */
+png_infop
+png_create_info_struct(png_structp png_ptr)
+{
+ png_infop info_ptr;
+
+ png_debug(1, "in png_create_info_struct\n");
+ if(png_ptr == NULL) return (NULL);
+#ifdef PNG_USER_MEM_SUPPORTED
+ if ((info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
+ png_ptr->malloc_fn)) != NULL)
+#else
+ if ((info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO)) != NULL)
+#endif
+ {
+ png_info_init(info_ptr);
+ }
+
+ return (info_ptr);
+}
+
+/* This function frees the memory associated with a single info struct.
+ * Normally, one would use either png_destroy_read_struct() or
+ * png_destroy_write_struct() to free an info struct, but this may be
+ * useful for some applications.
+ */
+void
+png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
+{
+ png_infop info_ptr = NULL;
+
+ png_debug(1, "in png_destroy_info_struct\n");
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+ png_info_destroy(png_ptr, info_ptr);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+}
+
+/* Initialize the info structure. This is now an internal function (0.89)
+ * and applications using it are urged to use png_create_info_struct()
+ * instead.
+ */
+void
+png_info_init(png_infop info_ptr)
+{
+ png_debug(1, "in png_info_init\n");
+ /* set everything to 0 */
+ png_memset(info_ptr, 0, sizeof (png_info));
+}
+
+/* This is an internal routine to free any memory that the info struct is
+ * pointing to before re-using it or freeing the struct itself. Recall
+ * that png_free() checks for NULL pointers for us.
+ */
+void
+png_info_destroy(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+ png_debug(1, "in png_info_destroy\n");
+ if (info_ptr->text != NULL)
+ {
+ int i;
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_free(png_ptr, info_ptr->text[i].key);
+ }
+ png_free(png_ptr, info_ptr->text);
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ png_free(png_ptr, info_ptr->pcal_purpose);
+ png_free(png_ptr, info_ptr->pcal_units);
+ if (info_ptr->pcal_params != NULL)
+ {
+ int i;
+ for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
+ {
+ png_free(png_ptr, info_ptr->pcal_params[i]);
+ }
+ png_free(png_ptr, info_ptr->pcal_params);
+ }
+#endif
+
+ png_info_init(info_ptr);
+}
+
+/* This function returns a pointer to the io_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy() or png_read_destroy() are called.
+ */
+png_voidp
+png_get_io_ptr(png_structp png_ptr)
+{
+ return (png_ptr->io_ptr);
+}
+
+#if !defined(PNG_NO_STDIO)
+/* Initialize the default input/output functions for the PNG file. If you
+ * use your own read or write routines, you can call either png_set_read_fn()
+ * or png_set_write_fn() instead of png_init_io().
+ */
+void
+png_init_io(png_structp png_ptr, FILE *fp)
+{
+ png_debug(1, "in png_init_io\n");
+ png_ptr->io_ptr = (png_voidp)fp;
+}
+#endif
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+/* Convert the supplied time into an RFC 1123 string suitable for use in
+ * a "Creation Time" or other text-based time string.
+ */
+png_charp
+png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime)
+{
+ static PNG_CONST char short_months[12][4] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ if (png_ptr->time_buffer == NULL)
+ {
+ png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
+ sizeof(char)));
+ }
+
+#ifdef USE_FAR_KEYWORD
+ {
+ char near_time_buf[29];
+ sprintf(near_time_buf, "%d %s %d %02d:%02d:%02d +0000",
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+ png_memcpy(png_ptr->time_buffer, near_time_buf,
+ 29*sizeof(char));
+ }
+#else
+ sprintf(png_ptr->time_buffer, "%d %s %d %02d:%02d:%02d +0000",
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+#endif
+ return ((png_charp)png_ptr->time_buffer);
+}
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+
+png_charp
+png_get_copyright(png_structp png_ptr)
+{
+ if(png_ptr == NULL)
+ /* silence compiler warning about unused png_ptr */ ;
+ return("\n libpng version 1.0.3 - January 14, 1999\n\
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.\n\
+ Copyright (c) 1996, 1997 Andreas Dilger\n\
+ Copyright (c) 1998, 1999, Glenn Randers-Pehrson\n");
+}
--- /dev/null
+
+/* png.h - header file for PNG reference library
+ *
+ * libpng version 1.0.3 - January 14, 1999
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * Y2K compliance in libpng:
+ * =========================
+ *
+ * January 13, 1999
+ *
+ * Since the PNG Development group is an ad-hoc body, we can't make
+ * an official declaration.
+ *
+ * This is your unofficial assurance that libpng from version 0.81 and
+ * upward are Y2K compliant. It is my belief that earlier versions were
+ * also Y2K compliant.
+ *
+ * Libpng only has three year fields. One is a 2-byte unsigned integer
+ * that will hold years up to 65535. The other two hold the date in text
+ * format, and will hold years up to 9999.
+ *
+ * The integer is
+ * "png_uint_16 year" in png_time_struct.
+ *
+ * The strings are
+ * "png_charp time_buffer" in png_struct and
+ * "near_time_buffer", which is a local character string in png.c.
+ *
+ * There are seven time-related functions:
+ * png.c: png_convert_to_rfc_1123() in png.c
+ * (formerly png_convert_to_rfc_1152() in error)
+ * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ * png_convert_from_time_t() in pngwrite.c
+ * png_get_tIME() in pngget.c
+ * png_handle_tIME() in pngrutil.c, called in pngread.c
+ * png_set_tIME() in pngset.c
+ * png_write_tIME() in pngwutil.c, called in pngwrite.c
+ *
+ * All handle dates properly in a Y2K environment. The
+ * png_convert_from_time_t() function calls gmtime() to convert from system
+ * clock time, which returns (year - 1900), which we properly convert to
+ * the full 4-digit year. There is a possibility that applications using
+ * libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+ * function, or incorrectly passing only a 2-digit year instead of
+ * "year - 1900" into the png_convert_from_struct_tm() function, but this
+ * is not under our control. The libpng documentation has always stated
+ * that it works with 4-digit years, and the APIs have been documented as
+ * such.
+ *
+ * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+ * integer to hold the year, and can hold years as large as 65535.
+ *
+ *
+ * Glenn Randers-Pehrson
+ * libpng maintainer
+ * PNG Development Group
+ *
+ * Note about libpng version numbers:
+ *
+ * Due to various miscommunications, unforeseen code incompatibilities
+ * and occasional factors outside the authors' control, version numbering
+ * on the library has not always been consistent and straightforward.
+ * The following table summarizes matters since version 0.89c, which was
+ * the first widely used release:
+ *
+ * source png.h png.h shared-lib
+ * version string int version
+ * ------- ------ ----- ----------
+ * 0.89c ("1.0 beta 3") 0.89 89 1.0.89
+ * 0.90 ("1.0 beta 4") 0.90 90 0.90 [should have been 2.0.90]
+ * 0.95 ("1.0 beta 5") 0.95 95 0.95 [should have been 2.0.95]
+ * 0.96 ("1.0 beta 6") 0.96 96 0.96 [should have been 2.0.96]
+ * 0.97b ("1.00.97 beta 7") 1.00.97 97 1.0.1 [should have been 2.0.97]
+ * 0.97c 0.97 97 2.0.97
+ * 0.98 0.98 98 2.0.98
+ * 0.99 0.99 98 2.0.99
+ * 0.99a-m 0.99 99 2.0.99
+ * 1.00 1.00 100 2.1.0 [int should be 10000]
+ * 1.0.0 1.0.0 100 2.1.0 [int should be 10000]
+ * 1.0.1 1.0.1 10001 2.1.0
+ * 1.0.1a-e 1.0.1a-e 10002 2.1.0.1a-e
+ * 1.0.2 1.0.2 10002 2.1.0.2
+ * 1.0.2a-c 1.0.2a 10003 2.1.0.2a-c
+ * 1.0.3 1.0.3 10003 2.1.0.3
+ *
+ * Henceforth the source version will match the shared-library minor
+ * and patch numbers; the shared-library major version number will be
+ * used for changes in backward compatibility, as it is intended. The
+ * PNG_PNGLIB_VER macro, which is not used within libpng but is available
+ * for applications, is an unsigned integer of the form xyyzz corresponding
+ * to the source version x.y.z (leading zeros in y and z).
+ *
+ * See libpng.txt or libpng.3 for more information. The PNG specification
+ * is available as RFC 2083 <ftp://ftp.uu.net/graphics/png/documents/>
+ * and as a W3C Recommendation <http://www.w3.org/TR/REC.png.html>
+ *
+ * Contributing Authors:
+ * John Bowler
+ * Kevin Bracey
+ * Sam Bushell
+ * Andreas Dilger
+ * Magnus Holmgren
+ * Tom Lane
+ * Dave Martindale
+ * Glenn Randers-Pehrson
+ * Greg Roelofs
+ * Guy Eric Schalnat
+ * Paul Schmidt
+ * Tom Tanner
+ * Willem van Schaik
+ * Tim Wegner
+ *
+ * The contributing authors would like to thank all those who helped
+ * with testing, bug fixes, and patience. This wouldn't have been
+ * possible without all of you.
+ *
+ * Thanks to Frank J. T. Wojcik for helping with the documentation.
+ *
+ * COPYRIGHT NOTICE:
+ *
+ * The PNG Reference Library is supplied "AS IS". The Contributing Authors
+ * and Group 42, Inc. disclaim all warranties, expressed or implied,
+ * including, without limitation, the warranties of merchantability and of
+ * fitness for any purpose. The Contributing Authors and Group 42, Inc.
+ * assume no liability for direct, indirect, incidental, special, exemplary,
+ * or consequential damages, which may result from the use of the PNG
+ * Reference Library, even if advised of the possibility of such damage.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * source code, or portions hereof, for any purpose, without fee, subject
+ * to the following restrictions:
+ * 1. The origin of this source code must not be misrepresented.
+ * 2. Altered versions must be plainly marked as such and must not be
+ * misrepresented as being the original source.
+ * 3. This Copyright notice may not be removed or altered from any source or
+ * altered source distribution.
+ *
+ * The Contributing Authors and Group 42, Inc. specifically permit, without
+ * fee, and encourage the use of this source code as a component to
+ * supporting the PNG file format in commercial products. If you use this
+ * source code in a product, acknowledgment is not required but would be
+ * appreciated.
+ */
+
+
+#ifndef _PNG_H
+#define _PNG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* This is not the place to learn how to use libpng. The file libpng.txt
+ * describes how to use libpng, and the file example.c summarizes it
+ * with some code on which to build. This file is useful for looking
+ * at the actual function definitions and structure components.
+ */
+
+/* include the compression library's header */
+#include "zlib.h"
+
+/* include all user configurable info */
+#include "pngconf.h"
+
+/* This file is arranged in several sections. The first section contains
+ * structure and type definitions. The second section contains the external
+ * library functions, while the third has the internal library functions,
+ * which applications aren't expected to use directly.
+ */
+
+/* Version information for png.h - this should match the version in png.c */
+#define PNG_LIBPNG_VER_STRING "1.0.3"
+
+/* Careful here. At one time, Guy wanted to use 082, but that would be octal.
+ * We must not include leading zeros.
+ * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
+ * version 1.0.0 was mis-numbered 100 instead of 10000). From
+ * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=bugfix */
+#define PNG_LIBPNG_VER 10003 /* 1.0.3 */
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
+/* Version information for C files, stored in png.c. This had better match
+ * the version above.
+ */
+extern char png_libpng_ver[12]; /* need room for 99.99.99aa */
+
+/* Structures to facilitate easy interlacing. See png.c for more details */
+extern int FARDATA png_pass_start[7];
+extern int FARDATA png_pass_inc[7];
+extern int FARDATA png_pass_ystart[7];
+extern int FARDATA png_pass_yinc[7];
+extern int FARDATA png_pass_mask[7];
+extern int FARDATA png_pass_dsp_mask[7];
+/* These aren't currently used. If you need them, see png.c for more details
+extern int FARDATA png_pass_width[7];
+extern int FARDATA png_pass_height[7];
+*/
+
+#endif /* PNG_NO_EXTERN */
+
+/* Three color definitions. The order of the red, green, and blue, (and the
+ * exact size) is not important, although the size of the fields need to
+ * be png_byte or png_uint_16 (as defined below).
+ */
+typedef struct png_color_struct
+{
+ png_byte red;
+ png_byte green;
+ png_byte blue;
+} png_color;
+typedef png_color FAR * png_colorp;
+typedef png_color FAR * FAR * png_colorpp;
+
+typedef struct png_color_16_struct
+{
+ png_byte index; /* used for palette files */
+ png_uint_16 red; /* for use in red green blue files */
+ png_uint_16 green;
+ png_uint_16 blue;
+ png_uint_16 gray; /* for use in grayscale files */
+} png_color_16;
+typedef png_color_16 FAR * png_color_16p;
+typedef png_color_16 FAR * FAR * png_color_16pp;
+
+typedef struct png_color_8_struct
+{
+ png_byte red; /* for use in red green blue files */
+ png_byte green;
+ png_byte blue;
+ png_byte gray; /* for use in grayscale files */
+ png_byte alpha; /* for alpha channel files */
+} png_color_8;
+typedef png_color_8 FAR * png_color_8p;
+typedef png_color_8 FAR * FAR * png_color_8pp;
+
+/* png_text holds the text in a PNG file, and whether they are compressed
+ in the PNG file or not. The "text" field points to a regular C string. */
+typedef struct png_text_struct
+{
+ int compression; /* compression value, see PNG_TEXT_COMPRESSION_ */
+ png_charp key; /* keyword, 1-79 character description of "text" */
+ png_charp text; /* comment, may be an empty string (ie "") */
+ png_size_t text_length; /* length of "text" field */
+} png_text;
+typedef png_text FAR * png_textp;
+typedef png_text FAR * FAR * png_textpp;
+
+/* Supported compression types for text in PNG files (tEXt, and zTXt).
+ * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */
+#define PNG_TEXT_COMPRESSION_NONE_WR -3
+#define PNG_TEXT_COMPRESSION_zTXt_WR -2
+#define PNG_TEXT_COMPRESSION_NONE -1
+#define PNG_TEXT_COMPRESSION_zTXt 0
+#define PNG_TEXT_COMPRESSION_LAST 1 /* Not a valid value */
+
+/* png_time is a way to hold the time in an machine independent way.
+ * Two conversions are provided, both from time_t and struct tm. There
+ * is no portable way to convert to either of these structures, as far
+ * as I know. If you know of a portable way, send it to me. As a side
+ * note - PNG is Year 2000 compliant!
+ */
+typedef struct png_time_struct
+{
+ png_uint_16 year; /* full year, as in, 1995 */
+ png_byte month; /* month of year, 1 - 12 */
+ png_byte day; /* day of month, 1 - 31 */
+ png_byte hour; /* hour of day, 0 - 23 */
+ png_byte minute; /* minute of hour, 0 - 59 */
+ png_byte second; /* second of minute, 0 - 60 (for leap seconds) */
+} png_time;
+typedef png_time FAR * png_timep;
+typedef png_time FAR * FAR * png_timepp;
+
+/* png_info is a structure that holds the information in a PNG file so
+ * that the application can find out the characteristics of the image.
+ * If you are reading the file, this structure will tell you what is
+ * in the PNG file. If you are writing the file, fill in the information
+ * you want to put into the PNG file, then call png_write_info().
+ * The names chosen should be very close to the PNG specification, so
+ * consult that document for information about the meaning of each field.
+ *
+ * With libpng < 0.95, it was only possible to directly set and read the
+ * the values in the png_info_struct, which meant that the contents and
+ * order of the values had to remain fixed. With libpng 0.95 and later,
+ * however, there are now functions that abstract the contents of
+ * png_info_struct from the application, so this makes it easier to use
+ * libpng with dynamic libraries, and even makes it possible to use
+ * libraries that don't have all of the libpng ancillary chunk-handing
+ * functionality.
+ *
+ * In any case, the order of the parameters in png_info_struct should NOT
+ * be changed for as long as possible to keep compatibility with applications
+ * that use the old direct-access method with png_info_struct.
+ */
+typedef struct png_info_struct
+{
+ /* the following are necessary for every PNG file */
+ png_uint_32 width; /* width of image in pixels (from IHDR) */
+ png_uint_32 height; /* height of image in pixels (from IHDR) */
+ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */
+ png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */
+ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */
+ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
+ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */
+ png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
+ png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */
+ png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
+ png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
+ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+
+ /* The following is informational only on read, and not used on writes. */
+ png_byte channels; /* number of data channels per pixel (1, 3, 4)*/
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte spare_byte; /* to align the data, and for future use */
+ png_byte signature[8]; /* magic bytes read by libpng from start of file */
+
+ /* The rest of the data is optional. If you are reading, check the
+ * valid field to see if the information in these are valid. If you
+ * are writing, set the valid field to those chunks you want written,
+ * and initialize the appropriate fields below.
+ */
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED) || \
+ defined(PNG_READ_GAMMA_SUPPORTED)
+ /* The gAMA chunk describes the gamma characteristics of the system
+ * on which the image was created, normally in the range [1.0, 2.5].
+ * Data is valid if (valid & PNG_INFO_gAMA) is non-zero.
+ */
+ float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */
+#endif /* PNG_READ_gAMA_SUPPORTED || PNG_WRITE_gAMA_SUPPORTED */
+
+#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
+ /* GR-P, 0.96a */
+ /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */
+ png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */
+#endif /* PNG_READ_sRGB_SUPPORTED || PNG_WRITE_sRGB_SUPPORTED */
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* The tEXt and zTXt chunks contain human-readable textual data in
+ * uncompressed and compressed forms, respectively. The data in "text"
+ * is an array of pointers to uncompressed, null-terminated C strings.
+ * Each chunk has a keyword that describes the textual data contained
+ * in that chunk. Keywords are not required to be unique, and the text
+ * string may be empty. Any number of text chunks may be in an image.
+ */
+ int num_text; /* number of comments read/to write */
+ int max_text; /* current size of text array */
+ png_textp text; /* array of comments read/to write */
+#endif /* PNG_READ_OR_WRITE_tEXt_OR_zTXt_SUPPORTED */
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+ /* The tIME chunk holds the last time the displayed image data was
+ * modified. See the png_time struct for the contents of this struct.
+ */
+ png_time mod_time;
+#endif /* PNG_READ_tIME_SUPPORTED || PNG_WRITE_tIME_SUPPORTED */
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+ /* The sBIT chunk specifies the number of significant high-order bits
+ * in the pixel data. Values are in the range [1, bit_depth], and are
+ * only specified for the channels in the pixel data. The contents of
+ * the low-order bits is not specified. Data is valid if
+ * (valid & PNG_INFO_sBIT) is non-zero.
+ */
+ png_color_8 sig_bit; /* significant bits in color channels */
+#endif /* PNG_READ_sBIT_SUPPORTED || PNG_WRITE_sBIT_SUPPORTED */
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED) || \
+ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The tRNS chunk supplies transparency data for paletted images and
+ * other image types that don't need a full alpha channel. There are
+ * "num_trans" transparency values for a paletted image, stored in the
+ * same order as the palette colors, starting from index 0. Values
+ * for the data are in the range [0, 255], ranging from fully transparent
+ * to fully opaque, respectively. For non-paletted images, there is a
+ * single color specified that should be treated as fully transparent.
+ * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
+ */
+ png_bytep trans; /* transparent values for paletted image */
+ png_color_16 trans_values; /* transparent color for non-palette image */
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_WRITE_tRNS_SUPPORTED */
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED) || \
+ defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The bKGD chunk gives the suggested image background color if the
+ * display program does not have its own background color and the image
+ * is needs to composited onto a background before display. The colors
+ * in "background" are normally in the same color space/depth as the
+ * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero.
+ */
+ png_color_16 background;
+#endif /* PNG_READ_bKGD_SUPPORTED || PNG_WRITE_bKGD_SUPPORTED */
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+ /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards
+ * and downwards from the top-left corner of the display, page, or other
+ * application-specific co-ordinate space. See the PNG_OFFSET_ defines
+ * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero.
+ */
+ png_uint_32 x_offset; /* x offset on page */
+ png_uint_32 y_offset; /* y offset on page */
+ png_byte offset_unit_type; /* offset units type */
+#endif /* PNG_READ_oFFs_SUPPORTED || PNG_WRITE_oFFs_SUPPORTED */
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+ /* The pHYs chunk gives the physical pixel density of the image for
+ * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_
+ * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero.
+ */
+ png_uint_32 x_pixels_per_unit; /* horizontal pixel density */
+ png_uint_32 y_pixels_per_unit; /* vertical pixel density */
+ png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
+#endif /* PNG_READ_pHYs_SUPPORTED || PNG_WRITE_pHYs_SUPPORTED */
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+ /* The hIST chunk contains the relative frequency or importance of the
+ * various palette entries, so that a viewer can intelligently select a
+ * reduced-color palette, if required. Data is an array of "num_palette"
+ * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)
+ * is non-zero.
+ */
+ png_uint_16p hist;
+#endif /* PNG_READ_hIST_SUPPORTED || PNG_WRITE_hIST_SUPPORTED */
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+ /* The cHRM chunk describes the CIE color characteristics of the monitor
+ * on which the PNG was created. This data allows the viewer to do gamut
+ * mapping of the input image to ensure that the viewer sees the same
+ * colors in the image as the creator. Values are in the range
+ * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero.
+ */
+ float x_white;
+ float y_white;
+ float x_red;
+ float y_red;
+ float x_green;
+ float y_green;
+ float x_blue;
+ float y_blue;
+#endif /* PNG_READ_cHRM_SUPPORTED || PNG_WRITE_cHRM_SUPPORTED */
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+ /* The pCAL chunk describes a transformation between the stored pixel
+ * values and original physcical data values used to create the image.
+ * The integer range [0, 2^bit_depth - 1] maps to the floating-point
+ * range given by [pcal_X0, pcal_X1], and are further transformed by a
+ * (possibly non-linear) transformation function given by "pcal_type"
+ * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_
+ * defines below, and the PNG-Group's Scientific Visualization extension
+ * chunks document png-scivis-19970203 for a complete description of the
+ * transformations and how they should be implemented, as well as the
+ * png-extensions document for a description of the ASCII parameter
+ * strings. Data values are valid if (valid & PNG_INFO_pCAL) non-zero.
+ */
+ png_charp pcal_purpose; /* pCAL chunk description string */
+ png_int_32 pcal_X0; /* minimum value */
+ png_int_32 pcal_X1; /* maximum value */
+ png_charp pcal_units; /* Latin-1 string giving physical units */
+ png_charpp pcal_params; /* ASCII strings containing parameter values */
+ png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */
+ png_byte pcal_nparams; /* number of parameters given in pcal_params */
+#endif /* PNG_READ_pCAL_SUPPORTED || PNG_WRITE_pCAL_SUPPORTED */
+} png_info;
+typedef png_info FAR * png_infop;
+typedef png_info FAR * FAR * png_infopp;
+
+/* These describe the color_type field in png_info. */
+/* color type masks */
+#define PNG_COLOR_MASK_PALETTE 1
+#define PNG_COLOR_MASK_COLOR 2
+#define PNG_COLOR_MASK_ALPHA 4
+
+/* color types. Note that not all combinations are legal */
+#define PNG_COLOR_TYPE_GRAY 0
+#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
+
+/* This is for compression type. PNG 1.0 only defines the single type. */
+#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */
+#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE
+
+/* This is for filter type. PNG 1.0 only defines the single type. */
+#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */
+#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE
+
+/* These are for the interlacing type. These values should NOT be changed. */
+#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */
+#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */
+#define PNG_INTERLACE_LAST 2 /* Not a valid value */
+
+/* These are for the oFFs chunk. These values should NOT be changed. */
+#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */
+#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */
+#define PNG_OFFSET_LAST 2 /* Not a valid value */
+
+/* These are for the pCAL chunk. These values should NOT be changed. */
+#define PNG_EQUATION_LINEAR 0 /* Linear transformation */
+#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */
+#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */
+#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */
+#define PNG_EQUATION_LAST 4 /* Not a valid value */
+
+/* These are for the pHYs chunk. These values should NOT be changed. */
+#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */
+#define PNG_RESOLUTION_METER 1 /* pixels/meter */
+#define PNG_RESOLUTION_LAST 2 /* Not a valid value */
+
+/* These are for the sRGB chunk. These values should NOT be changed. */
+#define PNG_sRGB_INTENT_SATURATION 0
+#define PNG_sRGB_INTENT_PERCEPTUAL 1
+#define PNG_sRGB_INTENT_ABSOLUTE 2
+#define PNG_sRGB_INTENT_RELATIVE 3
+#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */
+
+
+
+/* These determine if an ancillary chunk's data has been successfully read
+ * from the PNG header, or if the application has filled in the corresponding
+ * data in the info_struct to be written into the output file. The values
+ * of the PNG_INFO_<chunk> defines should NOT be changed.
+ */
+#define PNG_INFO_gAMA 0x0001
+#define PNG_INFO_sBIT 0x0002
+#define PNG_INFO_cHRM 0x0004
+#define PNG_INFO_PLTE 0x0008
+#define PNG_INFO_tRNS 0x0010
+#define PNG_INFO_bKGD 0x0020
+#define PNG_INFO_hIST 0x0040
+#define PNG_INFO_pHYs 0x0080
+#define PNG_INFO_oFFs 0x0100
+#define PNG_INFO_tIME 0x0200
+#define PNG_INFO_pCAL 0x0400
+#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */
+
+/* This is used for the transformation routines, as some of them
+ * change these values for the row. It also should enable using
+ * the routines for other purposes.
+ */
+typedef struct png_row_info_struct
+{
+ png_uint_32 width; /* width of row */
+ png_uint_32 rowbytes; /* number of bytes in row */
+ png_byte color_type; /* color type of row */
+ png_byte bit_depth; /* bit depth of row */
+ png_byte channels; /* number of channels (1, 2, 3, or 4) */
+ png_byte pixel_depth; /* bits per pixel (depth * channels) */
+} png_row_info;
+
+typedef png_row_info FAR * png_row_infop;
+typedef png_row_info FAR * FAR * png_row_infopp;
+
+/* These are the function types for the I/O functions and for the functions
+ * that allow the user to override the default I/O functions with his or her
+ * own. The png_error_ptr type should match that of user-supplied warning
+ * and error functions, while the png_rw_ptr type should match that of the
+ * user read/write data functions.
+ */
+typedef struct png_struct_def png_struct;
+typedef png_struct FAR * png_structp;
+
+typedef void (*png_error_ptr) PNGARG((png_structp, png_const_charp));
+typedef void (*png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t));
+typedef void (*png_flush_ptr) PNGARG((png_structp));
+typedef void (*png_read_status_ptr) PNGARG((png_structp, png_uint_32, int));
+typedef void (*png_write_status_ptr) PNGARG((png_structp, png_uint_32, int));
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+typedef void (*png_progressive_info_ptr) PNGARG((png_structp, png_infop));
+typedef void (*png_progressive_end_ptr) PNGARG((png_structp, png_infop));
+typedef void (*png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
+ png_uint_32, int));
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+typedef void (*png_user_transform_ptr) PNGARG((png_structp,
+ png_row_infop, png_bytep));
+#endif /* PNG_READ|WRITE_USER_TRANSFORM_SUPPORTED */
+
+typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t));
+typedef void (*png_free_ptr) PNGARG((png_structp, png_structp));
+
+/* The structure that holds the information to read and write PNG files.
+ * The only people who need to care about what is inside of this are the
+ * people who will be modifying the library for their own special needs.
+ * It should NOT be accessed directly by an application, except to store
+ * the jmp_buf.
+ */
+
+struct png_struct_def
+{
+ jmp_buf jmpbuf; /* used in png_error */
+
+ png_error_ptr error_fn; /* function for printing errors and aborting */
+ png_error_ptr warning_fn; /* function for printing warnings */
+ png_voidp error_ptr; /* user supplied struct for error functions */
+ png_rw_ptr write_data_fn; /* function for writing output data */
+ png_rw_ptr read_data_fn; /* function for reading input data */
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ png_user_transform_ptr read_user_transform_fn; /* user read transform */
+ png_user_transform_ptr write_user_transform_fn; /* user write transform */
+#endif
+ png_voidp io_ptr; /* ptr to application struct for I/O functions*/
+
+ png_uint_32 mode; /* tells us where we are in the PNG file */
+ png_uint_32 flags; /* flags indicating various things to libpng */
+ png_uint_32 transformations; /* which transformations to perform */
+
+ z_stream zstream; /* pointer to decompression structure (below) */
+ png_bytep zbuf; /* buffer for zlib */
+ png_size_t zbuf_size; /* size of zbuf */
+ int zlib_level; /* holds zlib compression level */
+ int zlib_method; /* holds zlib compression method */
+ int zlib_window_bits; /* holds zlib compression window bits */
+ int zlib_mem_level; /* holds zlib compression memory level */
+ int zlib_strategy; /* holds zlib compression strategy */
+
+ png_uint_32 width; /* width of image in pixels */
+ png_uint_32 height; /* height of image in pixels */
+ png_uint_32 num_rows; /* number of rows in current pass */
+ png_uint_32 usr_width; /* width of row at start of write */
+ png_uint_32 rowbytes; /* size of row in bytes */
+ png_uint_32 irowbytes; /* size of current interlaced row in bytes */
+ png_uint_32 iwidth; /* width of current interlaced row in pixels */
+ png_uint_32 row_number; /* current row in interlace pass */
+ png_bytep prev_row; /* buffer to save previous (unfiltered) row */
+ png_bytep row_buf; /* buffer to save current (unfiltered) row */
+ png_bytep sub_row; /* buffer to save "sub" row when filtering */
+ png_bytep up_row; /* buffer to save "up" row when filtering */
+ png_bytep avg_row; /* buffer to save "avg" row when filtering */
+ png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */
+ png_row_info row_info; /* used for transformation routines */
+
+ png_uint_32 idat_size; /* current IDAT size for read */
+ png_uint_32 crc; /* current chunk CRC value */
+ png_colorp palette; /* palette from the input file */
+ png_uint_16 num_palette; /* number of color entries in palette */
+ png_uint_16 num_trans; /* number of transparency values */
+ png_byte chunk_name[5]; /* null-terminated name of current chunk */
+ png_byte compression; /* file compression type (always 0) */
+ png_byte filter; /* file filter type (always 0) */
+ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+ png_byte pass; /* current interlace pass (0 - 6) */
+ png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */
+ png_byte color_type; /* color type of file */
+ png_byte bit_depth; /* bit depth of file */
+ png_byte usr_bit_depth; /* bit depth of users row */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte channels; /* number of channels in file */
+ png_byte usr_channels; /* channels at start of write */
+ png_byte sig_bytes; /* magic bytes read/written from start of file */
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+ png_uint_16 filler; /* filler bytes for pixel expansion */
+#endif /* PNG_READ_FILLER_SUPPORTED */
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ png_byte background_gamma_type;
+ float background_gamma;
+ png_color_16 background; /* background color in screen gamma space */
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_color_16 background_1; /* background normalized to gamma 1.0 */
+#endif /* PNG_READ_GAMMA && PNG_READ_bKGD_SUPPORTED */
+#endif /* PNG_READ_bKGD_SUPPORTED */
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_flush_ptr output_flush_fn;/* Function for flushing output */
+ png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
+ png_uint_32 flush_rows; /* number of rows written since last flush */
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ int gamma_shift; /* number of "insignificant" bits 16-bit gamma */
+ float gamma; /* file gamma value */
+ float screen_gamma; /* screen gamma value (display_gamma/viewing_gamma */
+#endif /* PNG_READ_GAMMA_SUPPORTED */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep gamma_table; /* gamma table for 8 bit depth files */
+ png_bytep gamma_from_1; /* converts from 1.0 to screen */
+ png_bytep gamma_to_1; /* converts from file to 1.0 */
+ png_uint_16pp gamma_16_table; /* gamma table for 16 bit depth files */
+ png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
+ png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
+#endif /* PNG_READ_GAMMA_SUPPORTED || PNG_WRITE_GAMMA_SUPPORTED */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined (PNG_READ_sBIT_SUPPORTED)
+ png_color_8 sig_bit; /* significant bits in each available channel */
+#endif /* PNG_READ_GAMMA_SUPPORTED || PNG_READ_sBIT_SUPPORTED */
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+ png_color_8 shift; /* shift for significant bit tranformation */
+#endif /* PNG_READ_SHIFT_SUPPORTED || PNG_WRITE_SHIFT_SUPPORTED */
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \
+ || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep trans; /* transparency values for paletted files */
+ png_color_16 trans_values; /* transparency values for non-paletted files */
+#endif /* PNG_READ|WRITE_tRNS_SUPPORTED||PNG_READ_EXPAND|BACKGROUND_SUPPORTED */
+ png_read_status_ptr read_row_fn; /* called after each row is decoded */
+ png_write_status_ptr write_row_fn; /* called after each row is encoded */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_progressive_info_ptr info_fn; /* called after header data fully read */
+ png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */
+ png_progressive_end_ptr end_fn; /* called after image is complete */
+ png_bytep save_buffer_ptr; /* current location in save_buffer */
+ png_bytep save_buffer; /* buffer for previously read data */
+ png_bytep current_buffer_ptr; /* current location in current_buffer */
+ png_bytep current_buffer; /* buffer for recently used data */
+ png_uint_32 push_length; /* size of current input chunk */
+ png_uint_32 skip_length; /* bytes to skip in input data */
+ png_size_t save_buffer_size; /* amount of data now in save_buffer */
+ png_size_t save_buffer_max; /* total size of save_buffer */
+ png_size_t buffer_size; /* total amount of available input data */
+ png_size_t current_buffer_size; /* amount of data now in current_buffer */
+ int process_mode; /* what push library is currently doing */
+ int cur_palette; /* current push library palette index */
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+ png_size_t current_text_size; /* current size of text input data */
+ png_size_t current_text_left; /* how much text left to read in input */
+ png_charp current_text; /* current text chunk buffer */
+ png_charp current_text_ptr; /* current location in current_text */
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_READ_tEXt/zTXt_SUPPORTED */
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* for the Borland special 64K segment handler */
+ png_bytepp offset_table_ptr;
+ png_bytep offset_table;
+ png_uint_16 offset_table_number;
+ png_uint_16 offset_table_count;
+ png_uint_16 offset_table_count_free;
+#endif /* __TURBOC__&&!_Windows&&!__FLAT__ */
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_bytep palette_lookup; /* lookup table for dithering */
+ png_bytep dither_index; /* index translation for palette files */
+#endif /* PNG_READ_DITHER_SUPPORTED */
+#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_READ_hIST_SUPPORTED)
+ png_uint_16p hist; /* histogram */
+#endif
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_byte heuristic_method; /* heuristic for row filter selection */
+ png_byte num_prev_filters; /* number of weights for previous rows */
+ png_bytep prev_filters; /* filter type(s) of previous row(s) */
+ png_uint_16p filter_weights; /* weight(s) for previous line(s) */
+ png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
+ png_uint_16p filter_costs; /* relative filter calculation cost */
+ png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_charp time_buffer; /* String to hold RFC 1123 time text */
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_voidp mem_ptr; /* user supplied struct for mem functions */
+ png_malloc_ptr malloc_fn; /* function for allocating memory */
+ png_free_ptr free_fn; /* function for freeing memory */
+#endif /* PNG_USER_MEM_SUPPORTED */
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ png_byte rgb_to_gray_status;
+ png_byte rgb_to_gray_red_coeff;
+ png_byte rgb_to_gray_green_coeff;
+ png_byte rgb_to_gray_blue_coeff;
+#endif
+};
+
+typedef png_struct FAR * FAR * png_structpp;
+
+/* Here are the function definitions most commonly used. This is not
+ * the place to find out how to use libpng. See libpng.txt for the
+ * full explanation, see example.c for the summary. This just provides
+ * a simple one line of the use of each function.
+ */
+
+/* Tell lib we have already handled the first <num_bytes> magic bytes.
+ * Handling more than 8 bytes from the beginning of the file is an error.
+ */
+extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr,
+ int num_bytes));
+
+/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
+ * PNG file. Returns zero if the supplied bytes match the 8-byte PNG
+ * signature, and non-zero otherwise. Having num_to_check == 0 or
+ * start > 7 will always fail (ie return non-zero).
+ */
+extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start,
+ png_size_t num_to_check));
+
+/* Simple signature checking function. This is the same as calling
+ * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ */
+extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num));
+
+/* Allocate and initialize png_ptr struct for reading, and any other memory. */
+extern PNG_EXPORT(png_structp,png_create_read_struct)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn));
+
+/* Allocate and initialize png_ptr struct for writing, and any other memory */
+extern PNG_EXPORT(png_structp,png_create_write_struct)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn));
+
+#ifdef PNG_USER_MEM_SUPPORTED
+extern PNG_EXPORT(png_structp,png_create_read_struct_2)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+extern PNG_EXPORT(png_structp,png_create_write_struct_2)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+#endif
+
+/* Write a PNG chunk - size, type, (optional) data, CRC. */
+extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_bytep data, png_size_t length));
+
+/* Write the start of a PNG chunk - length and chunk name. */
+extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_uint_32 length));
+
+/* Write the data of a PNG chunk started with png_write_chunk_start(). */
+extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr,
+ png_bytep data, png_size_t length));
+
+/* Finish a chunk started with png_write_chunk_start() (includes CRC). */
+extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr));
+
+/* Allocate and initialize the info structure */
+extern PNG_EXPORT(png_infop,png_create_info_struct)
+ PNGARG((png_structp png_ptr));
+
+/* Initialize the info structure (old interface - NOT DLL EXPORTED) */
+extern void png_info_init PNGARG((png_infop info_ptr));
+
+/* Writes all the PNG information before the image. */
+extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read the information before the actual image data. */
+extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+extern PNG_EXPORT(png_charp,png_convert_to_rfc1123)
+ PNGARG((png_structp png_ptr, png_timep ptime));
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* convert from a struct tm to png_time */
+extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime,
+ struct tm FAR * ttime));
+
+/* convert from time_t to png_time. Uses gmtime() */
+extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime,
+ time_t ttime));
+#endif /* PNG_WRITE_tIME_SUPPORTED */
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha if available. */
+extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_EXPAND_SUPPORTED */
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* Use blue, green, red order for pixels. */
+extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_BGR_SUPPORTED || PNG_WRITE_BGR_SUPPORTED */
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* Expand the grayscale to 24 bit RGB if necessary. */
+extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* Reduce RGB to grayscale. */
+extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr,
+ int error_action, float red, float green ));
+extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp
+ png_ptr));
+#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */
+
+extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth,
+ png_colorp palette));
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_SWAP_ALPHA_SUPPORTED || PNG_WRITE_SWAP_ALPHA_SUPPORTED */
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED || PNG_WRITE_INVERT_ALPHA_SUPPORTED */
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte to 24-bit RGB images. */
+extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr,
+ png_uint_32 filler, int flags));
+
+/* The values of the PNG_FILLER_ defines should NOT be changed */
+#define PNG_FILLER_BEFORE 0
+#define PNG_FILLER_AFTER 1
+#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* Swap bytes in 16 bit depth files. */
+extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_SWAP_SUPPORTED || PNG_WRITE_SWAP_SUPPORTED */
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* Use 1 byte per pixel in 1, 2, or 4 bit depth files. */
+extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_PACK_SUPPORTED || PNG_WRITE_PACK_SUPPORTED */
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* Swap packing order of pixels in bytes. */
+extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_PACKSWAP_SUPPORTED || PNG_WRITE_PACKSWAP_SUPPOR */
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Converts files to legal bit depths. */
+extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr,
+ png_color_8p true_bits));
+#endif /* PNG_READ_SHIFT_SUPPORTED || PNG_WRITE_SHIFT_SUPPORTED */
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Have the code handle the interlacing. Returns the number of passes. */
+extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_INTERLACING_SUPPORTED || PNG_WRITE_INTERLACING_SUPPORTED */
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+/* Invert monocrome files */
+extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_INVERT_SUPPORTED || PNG_WRITE_INVERT_SUPPORTED */
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Handle alpha and tRNS by replacing with a background color. */
+extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma));
+#define PNG_BACKGROUND_GAMMA_UNKNOWN 0
+#define PNG_BACKGROUND_GAMMA_SCREEN 1
+#define PNG_BACKGROUND_GAMMA_FILE 2
+#define PNG_BACKGROUND_GAMMA_UNIQUE 3
+#endif /* PNG_READ_BACKGROUND_SUPPORTED */
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip the second byte of information from a 16 bit depth file. */
+extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr));
+#endif /* PNG_READ_16_TO_8_SUPPORTED */
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Turn on dithering, and reduce the palette to the number of colors available. */
+extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette, int maximum_colors,
+ png_uint_16p histogram, int full_dither));
+#endif /* PNG_READ_DITHER_SUPPORTED */
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Handle gamma correction. Screen_gamma=(display_gamma/viewing_gamma) */
+extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr,
+ double screen_gamma, double default_file_gamma));
+#endif /* PNG_READ_GAMMA_SUPPORTED */
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set how many lines between output flushes - 0 for no flushing */
+extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows));
+
+/* Flush the current PNG output buffer */
+extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr));
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+/* optional update palette with requested transformations */
+extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr));
+
+/* optional call to update the users info structure */
+extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read a one or more rows of image data.*/
+extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_bytepp display_row, png_uint_32 num_rows));
+
+/* read a row of data.*/
+extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr,
+ png_bytep row,
+ png_bytep display_row));
+
+/* read the whole image into memory at once. */
+extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+
+/* write a row of image data */
+extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr,
+ png_bytep row));
+
+/* write a few rows of image data */
+extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_uint_32 num_rows));
+
+/* write the image data */
+extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+
+/* writes the end of the PNG file. */
+extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read the end of the PNG file. */
+extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* free any memory associated with the png_info_struct */
+extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr,
+ png_infopp info_ptr_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp
+ png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
+
+/* free all memory used by the read (old method - NOT DLL EXPORTED) */
+extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_infop end_info_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_write_struct)
+ PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr));
+
+/* free any memory used in info_ptr struct (old method - NOT DLL EXPORTED) */
+extern void png_write_destroy_info PNGARG((png_infop info_ptr));
+
+/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */
+extern void png_write_destroy PNGARG((png_structp png_ptr));
+
+/* set the libpng method of handling chunk CRC errors */
+extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr,
+ int crit_action, int ancil_action));
+
+/* Values for png_set_crc_action() to say how to handle CRC errors in
+ * ancillary and critical chunks, and whether to use the data contained
+ * therein. Note that it is impossible to "discard" data in a critical
+ * chunk. For versions prior to 0.90, the action was always error/quit,
+ * whereas in version 0.90 and later, the action for CRC errors in ancillary
+ * chunks is warn/discard. These values should NOT be changed.
+ *
+ * value action:critical action:ancillary
+ */
+#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */
+#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */
+#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */
+#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */
+#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */
+#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */
+
+/* These functions give the user control over the scan-line filtering in
+ * libpng and the compression methods used by zlib. These functions are
+ * mainly useful for testing, as the defaults should work with most users.
+ * Those users who are tight on memory or want faster performance at the
+ * expense of compression can modify them. See the compression library
+ * header file (zlib.h) for an explination of the compression functions.
+ */
+
+/* set the filtering method(s) used by libpng. Currently, the only valid
+ * value for "method" is 0.
+ */
+extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
+ int filters));
+
+/* Flags for png_set_filter() to say which filters to use. The flags
+ * are chosen so that they don't conflict with real filter types
+ * below, in case they are supplied instead of the #defined constants.
+ * These values should NOT be changed.
+ */
+#define PNG_NO_FILTERS 0x00
+#define PNG_FILTER_NONE 0x08
+#define PNG_FILTER_SUB 0x10
+#define PNG_FILTER_UP 0x20
+#define PNG_FILTER_AVG 0x40
+#define PNG_FILTER_PAETH 0x80
+#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
+ PNG_FILTER_AVG | PNG_FILTER_PAETH)
+
+/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
+ * These defines should NOT be changed.
+ */
+#define PNG_FILTER_VALUE_NONE 0
+#define PNG_FILTER_VALUE_SUB 1
+#define PNG_FILTER_VALUE_UP 2
+#define PNG_FILTER_VALUE_AVG 3
+#define PNG_FILTER_VALUE_PAETH 4
+#define PNG_FILTER_VALUE_LAST 5
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */
+/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
+ * defines, either the default (minimum-sum-of-absolute-differences), or
+ * the experimental method (weighted-minimum-sum-of-absolute-differences).
+ *
+ * Weights are factors >= 1.0, indicating how important it is to keep the
+ * filter type consistent between rows. Larger numbers mean the current
+ * filter is that many times as likely to be the same as the "num_weights"
+ * previous filters. This is cumulative for each previous row with a weight.
+ * There needs to be "num_weights" values in "filter_weights", or it can be
+ * NULL if the weights aren't being specified. Weights have no influence on
+ * the selection of the first row filter. Well chosen weights can (in theory)
+ * improve the compression for a given image.
+ *
+ * Costs are factors >= 1.0 indicating the relative decoding costs of a
+ * filter type. Higher costs indicate more decoding expense, and are
+ * therefore less likely to be selected over a filter with lower computational
+ * costs. There needs to be a value in "filter_costs" for each valid filter
+ * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
+ * setting the costs. Costs try to improve the speed of decompression without
+ * unduly increasing the compressed image size.
+ *
+ * A negative weight or cost indicates the default value is to be used, and
+ * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
+ * The default values for both weights and costs are currently 1.0, but may
+ * change if good general weighting/cost heuristics can be found. If both
+ * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
+ * to the UNWEIGHTED method, but with added encoding time/computation.
+ */
+extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr,
+ int heuristic_method, int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs));
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+/* Heuristic used for row filter selection. These defines should NOT be
+ * changed.
+ */
+#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */
+#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */
+#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */
+#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */
+
+/* Set the library compression level. Currently, valid values range from
+ * 0 - 9, corresponding directly to the zlib compression levels 0 - 9
+ * (0 - no compression, 9 - "maximal" compression). Note that tests have
+ * shown that zlib compression levels 3-6 usually perform as well as level 9
+ * for PNG images, and do considerably fewer caclulations. In the future,
+ * these values may not correspond directly to the zlib compression levels.
+ */
+extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr,
+ int level));
+
+extern PNG_EXPORT(void,png_set_compression_mem_level)
+ PNGARG((png_structp png_ptr, int mem_level));
+
+extern PNG_EXPORT(void,png_set_compression_strategy)
+ PNGARG((png_structp png_ptr, int strategy));
+
+extern PNG_EXPORT(void,png_set_compression_window_bits)
+ PNGARG((png_structp png_ptr, int window_bits));
+
+extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr,
+ int method));
+
+/* These next functions are called for input/output, memory, and error
+ * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c,
+ * and call standard C I/O routines such as fread(), fwrite(), and
+ * fprintf(). These functions can be made to use other I/O routines
+ * at run time for those applications that need to handle I/O in a
+ * different manner by calling png_set_???_fn(). See libpng.txt for
+ * more information.
+ */
+
+#if !defined(PNG_NO_STDIO)
+/* Initialize the input/output for the PNG file to the default functions. */
+extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, FILE *fp));
+#endif
+
+/* Replace the (error and abort), and warning functions with user
+ * supplied functions. If no messages are to be printed you must still
+ * write and use replacement functions. The replacement error_fn should
+ * still do a longjmp to the last setjmp location if you are using this
+ * method of error handling. If error_fn or warning_fn is NULL, the
+ * default function will be used.
+ */
+
+extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
+
+/* Return the user pointer associated with the error functions */
+extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr));
+
+/* Replace the default data output functions with a user supplied one(s).
+ * If buffered output is not used, then output_flush_fn can be set to NULL.
+ * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
+ * output_flush_fn will be ignored (and thus can be NULL).
+ */
+extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
+
+/* Replace the default data input function with a user supplied one. */
+extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr read_data_fn));
+
+/* Return the user pointer associated with the I/O functions */
+extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr));
+
+extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr,
+ png_read_status_ptr read_row_fn));
+
+extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr,
+ png_write_status_ptr write_row_fn));
+
+#ifdef PNG_USER_MEM_SUPPORTED
+/* Replace the default memory allocation functions with user supplied one(s). */
+extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr,
+ png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+
+/* Return the user pointer associated with the memory functions */
+extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr));
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
+extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp
+ png_ptr, png_user_transform_ptr read_user_transform_fn));
+#endif
+
+#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
+extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp
+ png_ptr, png_user_transform_ptr write_user_transform_fn));
+#endif
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+/* Sets the function callbacks for the push reader, and a pointer to a
+ * user-defined structure available to the callback functions.
+ */
+extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn));
+
+/* returns the user pointer associated with the push read functions */
+extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
+ PNGARG((png_structp png_ptr));
+
+/* function to be called when data becomes available */
+extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep buffer, png_size_t buffer_size));
+
+/* function that combines rows. Not very much different than the
+ * png_combine_row() call. Is this even used?????
+ */
+extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row));
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+
+/* frees a pointer allocated by png_malloc() */
+extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr));
+
+#ifdef PNG_USER_MEM_SUPPORTED
+extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr,
+ png_voidp ptr));
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr,
+ png_voidp s1, png_voidp s2, png_uint_32 size));
+
+extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr,
+ png_voidp s1, int value, png_uint_32 size));
+
+#if defined(USE_FAR_KEYWORD) /* memory model conversion function */
+extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr,
+ int check));
+#endif /* USE_FAR_KEYWORD */
+
+/* Fatal error in PNG image of libpng - can't continue */
+extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr,
+ png_const_charp error));
+
+/* The same, but the chunk name is prepended to the error string. */
+extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr,
+ png_const_charp error));
+
+/* Non-fatal error in libpng. Can continue, but may have a problem. */
+extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* Non-fatal error in libpng, chunk name is prepended to message. */
+extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* The png_set_<chunk> functions are for storing values in the png_info_struct.
+ * Similarly, the png_get_<chunk> calls are used to read values from the
+ * png_info_struct, either storing the parameters in the passed variables, or
+ * setting pointers into the png_info_struct where the data is stored. The
+ * png_get_<chunk> functions return a non-zero value if the data was available
+ * in info_ptr, or return zero and do not change any of the parameters if the
+ * data was not available.
+ *
+ * These functions should be used instead of directly accessing png_info
+ * to avoid problems with future changes in the size and internal layout of
+ * png_info_struct.
+ */
+/* Returns "flag" if chunk data is valid in info_ptr. */
+extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr,
+png_infop info_ptr, png_uint_32 flag));
+
+/* Returns number of bytes needed to hold a transformed row. */
+extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+/* Returns number of color channels in image. */
+extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+/* Returns image width in pixels. */
+extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image height in pixels. */
+extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image bit_depth. */
+extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image color_type. */
+extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image filter_type. */
+extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image interlace_type. */
+extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image compression_type. */
+extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image resolution in pixels per meter, from pHYs chunk data. */
+extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns pixel aspect ratio, computed from pHYs chunk data. */
+extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
+extern PNG_EXPORT(png_uint_32, png_get_x_offset_pixels) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_y_offset_pixels) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_x_offset_microns) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_y_offset_microns) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+#endif /* PNG_EASY_ACCESS_SUPPORTED */
+
+/* Returns pointer to signature string read from PNG header */
+extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p *background));
+#endif /* PNG_READ_bKGD_SUPPORTED */
+
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
+extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p background));
+#endif /* PNG_READ_bKGD_SUPPORTED || PNG_WRITE_bKGD_SUPPORTED */
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *white_x, double *white_y, double *red_x,
+ double *red_y, double *green_x, double *green_y, double *blue_x,
+ double *blue_y));
+#endif /* PNG_READ_cHRM_SUPPORTED */
+
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double white_x, double white_y, double red_x,
+ double red_y, double green_x, double green_y, double blue_x, double blue_y));
+#endif /* PNG_READ_cHRM_SUPPORTED || PNG_WRITE_cHRM_SUPPORTED */
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *file_gamma));
+#endif /* PNG_READ_gAMA_SUPPORTED */
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double file_gamma));
+#endif /* PNG_READ_gAMA_SUPPORTED || PNG_WRITE_gAMA_SUPPORTED */
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p *hist));
+#endif /* PNG_READ_hIST_SUPPORTED */
+
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p hist));
+#endif /* PNG_READ_hIST_SUPPORTED || PNG_WRITE_hIST_SUPPORTED */
+
+extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *width, png_uint_32 *height,
+ int *bit_depth, int *color_type, int *interlace_type,
+ int *compression_type, int *filter_type));
+
+extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type, int filter_type));
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *offset_x, png_uint_32 *offset_y,
+ int *unit_type));
+#endif /* PNG_READ_oFFs_SUPPORTED */
+
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 offset_x, png_uint_32 offset_y,
+ int unit_type));
+#endif /* PNG_READ_oFFs_SUPPORTED || PNG_WRITE_oFFs_SUPPORTED */
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
+ int *type, int *nparams, png_charp *units, png_charpp *params));
+#endif /* PNG_READ_pCAL_SUPPORTED */
+
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1,
+ int type, int nparams, png_charp units, png_charpp params));
+#endif /* PNG_READ_pCAL_SUPPORTED || PNG_WRITE_pCAL_SUPPORTED */
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
+#endif /* PNG_READ_pHYs_SUPPORTED */
+
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+#endif /* PNG_READ_pHYs_SUPPORTED || PNG_WRITE_pHYs_SUPPORTED */
+
+extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp *palette, int *num_palette));
+
+extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp palette, int num_palette));
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p *sig_bit));
+#endif /* PNG_READ_sBIT_SUPPORTED */
+
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p sig_bit));
+#endif /* PNG_READ_sBIT_SUPPORTED || PNG_WRITE_sBIT_SUPPORTED */
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int *intent));
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int intent));
+extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int intent));
+#endif /* PNG_READ_sRGB_SUPPORTED || PNG_WRITE_sRGB_SUPPORTED */
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+/* png_get_text also returns the number of text chunks in text_ptr */
+extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp *text_ptr, int *num_text));
+#endif /* PNG_READ_tEXt_SUPPORTED || PNG_READ_zTXt_SUPPORTED */
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp text_ptr, int num_text));
+#endif /* PNG_READ_OR_WRITE_tEXt_OR_zTXt_SUPPORTED */
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep *mod_time));
+#endif /* PNG_READ_tIME_SUPPORTED */
+
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep mod_time));
+#endif /* PNG_READ_tIME_SUPPORTED || PNG_WRITE_tIME_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep *trans, int *num_trans,
+ png_color_16p *trans_values));
+#endif /* PNG_READ_tRNS_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep trans, int num_trans,
+ png_color_16p trans_values));
+#endif /* PNG_READ_tRNS_SUPPORTED || PNG_WRITE_tRNS_SUPPORTED */
+
+/* Define PNG_DEBUG at compile time for debugging information. Higher
+ * numbers for PNG_DEBUG mean more debugging information. This has
+ * only been added since version 0.95 so it is not implemented throughout
+ * libpng yet, but more support will be added as needed.
+ */
+#ifdef PNG_DEBUG
+#if (PNG_DEBUG > 0)
+#ifndef PNG_DEBUG_FILE
+#define PNG_DEBUG_FILE stderr
+#endif /* PNG_DEBUG_FILE */
+
+#define png_debug(l,m) if (PNG_DEBUG > l) \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+ (l==2 ? "\t\t":(l>2 ? "\t\t\t":""))))
+#define png_debug1(l,m,p1) if (PNG_DEBUG > l) \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+ (l==2 ? "\t\t":(l>2 ? "\t\t\t":""))),p1)
+#define png_debug2(l,m,p1,p2) if (PNG_DEBUG > l) \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(l==1 ? "\t" : \
+ (l==2 ? "\t\t":(l>2 ? "\t\t\t":""))),p1,p2)
+#endif /* (PNG_DEBUG > 0) */
+#endif /* PNG_DEBUG */
+#ifndef png_debug
+#define png_debug(l, m)
+#endif
+#ifndef png_debug1
+#define png_debug1(l, m, p1)
+#endif
+#ifndef png_debug2
+#define png_debug2(l, m, p1, p2)
+#endif
+
+extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr));
+
+#ifdef PNG_NO_EXTERN
+/* this only gets included in png.c */
+png_charp
+png_get_header_version(png_structp png_ptr)
+{
+ if(png_ptr == NULL)
+ /* silence compiler warning about unused png_ptr */ ;
+ return("\n libpng version 1.0.3 - January 14, 1999 (header)\n");
+}
+#endif
+
+#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED
+/* With these routines we avoid an integer divide, which will be slower on
+ * most machines. However, it does take more operations than the corresponding
+ * divide method, so it may be slower on a few RISC systems. There are two
+ * shifts (by 8 or 16 bits) and an addition, versus a single integer divide.
+ *
+ * Note that the rounding factors are NOT supposed to be the same! 128 and
+ * 32768 are correct for the NODIV code; 127 and 32767 are correct for the
+ * standard method.
+ *
+ * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ]
+ */
+
+ /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */
+
+# define png_composite(composite, fg, alpha, bg) \
+ { png_uint_16 temp = ((png_uint_16)(fg) * (png_uint_16)(alpha) + \
+ (png_uint_16)(bg)*(png_uint_16)(255 - \
+ (png_uint_16)(alpha)) + (png_uint_16)128); \
+ (composite) = (png_byte)((temp + (temp >> 8)) >> 8); }
+
+# define png_composite_16(composite, fg, alpha, bg) \
+ { png_uint_32 temp = ((png_uint_32)(fg) * (png_uint_32)(alpha) + \
+ (png_uint_32)(bg)*(png_uint_32)(65535L - \
+ (png_uint_32)(alpha)) + (png_uint_32)32768L); \
+ (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); }
+
+#else /* standard method using integer division */
+
+# define png_composite(composite, fg, alpha, bg) \
+ (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \
+ (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \
+ (png_uint_16)127) / 255)
+
+# define png_composite_16(composite, fg, alpha, bg) \
+ (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \
+ (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \
+ (png_uint_32)32767) / (png_uint_32)65535L)
+
+#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */
+
+/* These next functions are used internally in the code. They generally
+ * shouldn't be used unless you are writing code to add or replace some
+ * functionality in libpng. More information about most functions can
+ * be found in the files where the functions are located.
+ */
+
+#if defined(PNG_INTERNAL)
+
+/* Various modes of operation. Note that after an init, mode is set to
+ * zero automatically when the structure is created.
+ */
+#define PNG_BEFORE_IHDR 0x00
+#define PNG_HAVE_IHDR 0x01
+#define PNG_HAVE_PLTE 0x02
+#define PNG_HAVE_IDAT 0x04
+#define PNG_AFTER_IDAT 0x08
+#define PNG_HAVE_IEND 0x10
+#define PNG_HAVE_gAMA 0x20
+#define PNG_HAVE_cHRM 0x40
+#define PNG_HAVE_sRGB 0x80
+
+/* push model modes */
+#define PNG_READ_SIG_MODE 0
+#define PNG_READ_CHUNK_MODE 1
+#define PNG_READ_IDAT_MODE 2
+#define PNG_SKIP_MODE 3
+#define PNG_READ_tEXt_MODE 4
+#define PNG_READ_zTXt_MODE 5
+#define PNG_READ_DONE_MODE 6
+#define PNG_ERROR_MODE 7
+
+/* flags for the transformations the PNG library does on the image data */
+#define PNG_BGR 0x0001
+#define PNG_INTERLACE 0x0002
+#define PNG_PACK 0x0004
+#define PNG_SHIFT 0x0008
+#define PNG_SWAP_BYTES 0x0010
+#define PNG_INVERT_MONO 0x0020
+#define PNG_DITHER 0x0040
+#define PNG_BACKGROUND 0x0080
+#define PNG_BACKGROUND_EXPAND 0x0100
+ /* 0x0200 unused */
+#define PNG_16_TO_8 0x0400
+#define PNG_RGBA 0x0800
+#define PNG_EXPAND 0x1000
+#define PNG_GAMMA 0x2000
+#define PNG_GRAY_TO_RGB 0x4000
+#define PNG_FILLER 0x8000
+#define PNG_PACKSWAP 0x10000L
+#define PNG_SWAP_ALPHA 0x20000L
+#define PNG_STRIP_ALPHA 0x40000L
+#define PNG_INVERT_ALPHA 0x80000L
+#define PNG_USER_TRANSFORM 0x100000L
+#define PNG_RGB_TO_GRAY_ERR 0x200000L
+#define PNG_RGB_TO_GRAY_WARN 0x400000L
+#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */
+
+/* flags for png_create_struct */
+#define PNG_STRUCT_PNG 0x0001
+#define PNG_STRUCT_INFO 0x0002
+
+/* Scaling factor for filter heuristic weighting calculations */
+#define PNG_WEIGHT_SHIFT 8
+#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
+#define PNG_COST_SHIFT 3
+#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
+
+/* flags for the png_ptr->flags rather than declaring a byte for each one */
+#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001
+#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002
+#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004
+#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008
+#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010
+#define PNG_FLAG_ZLIB_FINISHED 0x0020
+#define PNG_FLAG_ROW_INIT 0x0040
+#define PNG_FLAG_FILLER_AFTER 0x0080
+#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100
+#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200
+#define PNG_FLAG_CRC_CRITICAL_USE 0x0400
+#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800
+#define PNG_FLAG_FREE_PALETTE 0x1000
+#define PNG_FLAG_FREE_TRANS 0x2000
+#define PNG_FLAG_FREE_HIST 0x4000
+#define PNG_FLAG_HAVE_CHUNK_HEADER 0x8000L
+#define PNG_FLAG_WROTE_tIME 0x10000L
+#define PNG_FLAG_BACKGROUND_IS_GRAY 0x20000L
+
+#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
+ PNG_FLAG_CRC_ANCILLARY_NOWARN)
+
+#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \
+ PNG_FLAG_CRC_CRITICAL_IGNORE)
+
+#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \
+ PNG_FLAG_CRC_CRITICAL_MASK)
+
+/* save typing and make code easier to understand */
+#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \
+ abs((int)((c1).green) - (int)((c2).green)) + \
+ abs((int)((c1).blue) - (int)((c2).blue)))
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
+/* place to hold the signature string for a PNG file. */
+extern png_byte FARDATA png_sig[8];
+
+/* Constant strings for known chunk types. If you need to add a chunk,
+ * add a string holding the name here. See png.c for more details. We
+ * can't selectively include these, since we still check for chunk in the
+ * wrong locations with these labels.
+ */
+extern png_byte FARDATA png_IHDR[5];
+extern png_byte FARDATA png_IDAT[5];
+extern png_byte FARDATA png_IEND[5];
+extern png_byte FARDATA png_PLTE[5];
+extern png_byte FARDATA png_bKGD[5];
+extern png_byte FARDATA png_cHRM[5];
+extern png_byte FARDATA png_gAMA[5];
+extern png_byte FARDATA png_hIST[5];
+extern png_byte FARDATA png_oFFs[5];
+extern png_byte FARDATA png_pCAL[5];
+extern png_byte FARDATA png_pHYs[5];
+extern png_byte FARDATA png_sBIT[5];
+extern png_byte FARDATA png_sRGB[5];
+extern png_byte FARDATA png_tEXt[5];
+extern png_byte FARDATA png_tIME[5];
+extern png_byte FARDATA png_tRNS[5];
+extern png_byte FARDATA png_zTXt[5];
+
+#endif /* PNG_NO_EXTERN */
+
+/* Inline macros to do direct reads of bytes from the input buffer. These
+ * require that you are using an architecture that uses PNG byte ordering
+ * (MSB first) and supports unaligned data storage. I think that PowerPC
+ * in big-endian mode and 680x0 are the only ones that will support this.
+ * The x86 line of processors definitely do not. The png_get_int_32()
+ * routine also assumes we are using two's complement format for negative
+ * values, which is almost certainly true.
+ */
+#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED)
+#if defined(PNG_READ_pCAL_SUPPORTED)
+#define png_get_int_32(buf) ( *((png_int_32p) (buf)))
+#endif /* PNG_READ_pCAL_SUPPORTED */
+#define png_get_uint_32(buf) ( *((png_uint_32p) (buf)))
+#define png_get_uint_16(buf) ( *((png_uint_16p) (buf)))
+#else
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf));
+#endif /* PNG_READ_pCAL_SUPPORTED */
+PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf));
+PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf));
+#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
+
+/* Initialize png_ptr struct for reading, and allocate any other memory.
+ * (old interface - NOT DLL EXPORTED).
+ */
+extern void png_read_init PNGARG((png_structp png_ptr));
+
+/* Initialize png_ptr struct for writing, and allocate any other memory.
+ * (old interface - NOT DLL EXPORTED).
+ */
+extern void png_write_init PNGARG((png_structp png_ptr));
+
+/* allocate memory for an internal libpng struct */
+PNG_EXTERN png_voidp png_create_struct PNGARG((int type));
+
+/* free memory from internal libpng struct */
+PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr));
+
+PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr
+ malloc_fn));
+PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr,
+ png_free_ptr free_fn));
+
+/* free any memory that info_ptr points to and reset struct. */
+PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* Function to allocate memory for zlib. */
+PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size));
+
+/* function to free memory for zlib */
+PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr));
+
+/* reset the CRC variable */
+PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr));
+
+/* Write the "data" buffer to whatever output you are using. */
+PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* Read data from whatever input you are using into the "data" buffer */
+PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* read bytes into buf, and update png_ptr->crc */
+PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
+ png_size_t length));
+
+/* read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
+PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip));
+
+/* read the CRC from the file and compare it to the libpng calculated CRC */
+PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr));
+
+/* Calculate the CRC over a section of data. Note that we are only
+ * passing a maximum of 64K on systems that have this as a memory limit,
+ * since this is the maximum buffer size we can specify.
+ */
+PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr,
+ png_size_t length));
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+PNG_EXTERN void png_flush PNGARG((png_structp png_ptr));
+#endif
+
+/* Place a 32-bit number into a buffer in PNG byte order (big-endian).
+ * The only currently known PNG chunks that use signed numbers are
+ * the ancillary extension chunks, oFFs and pCAL.
+ */
+PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i));
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i));
+#endif
+
+/* Place a 16 bit number into a buffer in PNG byte order.
+ * The parameter is declared unsigned int, not png_uint_16,
+ * just to avoid potential problems on pre-ANSI C compilers.
+ */
+PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i));
+
+/* simple function to write the signature */
+PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr));
+
+/* write various chunks */
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ * information.
+ */
+PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width,
+ png_uint_32 height,
+ int bit_depth, int color_type, int compression_type, int filter_type,
+ int interlace_type));
+
+PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette,
+ png_uint_32 num_pal));
+
+PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit,
+ int color_type));
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr,
+ double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y));
+#endif
+
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr,
+ int intent));
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans,
+ png_color_16p values, int number, int color_type));
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr,
+ png_color_16p values, int color_type));
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist,
+ int num_hist));
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) || \
+ defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
+ png_charp key, png_charpp new_key));
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len));
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len, int compression));
+#endif
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr,
+ png_uint_32 x_offset, png_uint_32 y_offset, int unit_type));
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose,
+ png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params));
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr,
+ png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
+ int unit_type));
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr,
+ png_timep mod_time));
+#endif
+
+/* Called when finished processing a row of data */
+PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
+
+/* Internal use only. Called before first row of data */
+PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr));
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr));
+#endif
+
+/* combine a row of data, dealing with alpha, etc. if requested */
+PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row,
+ int mask));
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+/* expand an interlaced row */
+PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass, png_uint_32 transformations));
+#endif
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* grab pixels out of a row for an interlaced pass */
+PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass));
+#endif
+
+/* unfilter a row */
+PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr,
+ png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter));
+
+/* Choose the best filter to use and filter the row data */
+PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr,
+ png_row_infop row_info));
+
+/* Write out the filtered row. */
+PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr,
+ png_bytep filtered_row));
+/* finish a row while reading, dealing with interlacing passes, etc. */
+PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr));
+
+/* initialize the row buffers, etc. */
+PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
+/* optional call to update the users info structure */
+PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* these are the functions that do the transformations */
+#if defined(PNG_READ_FILLER_SUPPORTED)
+PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 filler, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop
+ row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p sig_bits));
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info,
+ png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup));
+
+# if defined(PNG_CORRECT_PALETTE_SUPPORTED)
+PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette));
+# endif
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 bit_depth));
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p bit_depth));
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background,
+ png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift));
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift));
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info,
+ png_bytep row, png_colorp palette, png_bytep trans, int num_trans));
+PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info,
+ png_bytep row, png_color_16p trans_value));
+#endif
+
+/* The following decodes the appropriate chunks, and does error correction,
+ * then calls the appropriate callback for the chunk if it is valid.
+ */
+
+/* decode the IHDR chunk */
+PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+
+PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
+ png_bytep chunk_name));
+
+/* handle the transformations for reading and writing */
+PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr));
+
+PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t length));
+PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row));
+PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr));
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+#endif /* PNG_INTERNAL */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* do not put anything past this line */
+#endif /* _PNG_H */
--- /dev/null
+
+/* pngconf.h - machine configurable file for libpng
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ */
+
+/* Any machine specific code is near the front of this file, so if you
+ * are configuring libpng for a machine, you may want to read the section
+ * starting here down to where it starts to typedef png_color, png_text,
+ * and png_info.
+ */
+
+#ifndef PNGCONF_H
+#define PNGCONF_H
+
+
+/* This is the size of the compression buffer, and thus the size of
+ * an IDAT chunk. Make this whatever size you feel is best for your
+ * machine. One of these will be allocated per png_struct. When this
+ * is full, it writes the data to the disk, and does some other
+ * calculations. Making this an extremely small size will slow
+ * the library down, but you may want to experiment to determine
+ * where it becomes significant, if you are concerned with memory
+ * usage. Note that zlib allocates at least 32Kb also. For readers,
+ * this describes the size of the buffer available to read the data in.
+ * Unless this gets smaller than the size of a row (compressed),
+ * it should not make much difference how big this is.
+ */
+
+#ifndef PNG_ZBUF_SIZE
+#define PNG_ZBUF_SIZE 8192
+#endif
+
+/* If you are running on a machine where you cannot allocate more
+ * than 64K of memory at once, uncomment this. While libpng will not
+ * normally need that much memory in a chunk (unless you load up a very
+ * large file), zlib needs to know how big of a chunk it can use, and
+ * libpng thus makes sure to check any memory allocation to verify it
+ * will fit into memory.
+#define PNG_MAX_MALLOC_64K
+ */
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+#define PNG_MAX_MALLOC_64K
+#endif
+
+/* This protects us against compilers that run on a windowing system
+ * and thus don't have or would rather us not use the stdio types:
+ * stdin, stdout, and stderr. The only one currently used is stderr
+ * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will
+ * prevent these from being compiled and used. #defining PNG_NO_STDIO
+ * will also prevent these, plus will prevent the entire set of stdio
+ * macros and functions (FILE *, printf, etc.) from being compiled and used,
+ * unless PNG_DEBUG has been #defined.
+ *
+ * #define PNG_NO_CONSOLE_IO
+ * #define PNG_NO_STDIO
+ */
+
+#ifdef PNG_DEBUG
+# if (PNG_DEBUG > 0)
+# include <stdio.h>
+# endif
+#else
+# ifdef PNG_NO_STDIO
+# ifndef PNG_NO_CONSOLE_IO
+# define PNG_NO_CONSOLE_IO
+# endif
+# else
+# include <stdio.h>
+# endif
+#endif
+
+/* This macro protects us against machines that don't have function
+ * prototypes (ie K&R style headers). If your compiler does not handle
+ * function prototypes, define this macro and use the included ansi2knr.
+ * I've always been able to use _NO_PROTO as the indicator, but you may
+ * need to drag the empty declaration out in front of here, or change the
+ * ifdef to suit your own needs.
+ */
+#ifndef PNGARG
+
+#ifdef OF /* zlib prototype munger */
+#define PNGARG(arglist) OF(arglist)
+#else
+
+#ifdef _NO_PROTO
+#define PNGARG(arglist) ()
+#else
+#define PNGARG(arglist) arglist
+#endif /* _NO_PROTO */
+
+#endif /* OF */
+
+#endif /* PNGARG */
+
+/* Try to determine if we are compiling on a Mac. Note that testing for
+ * just __MWERKS__ is not good enough, because the Codewarrior is now used
+ * on non-Mac platforms.
+ */
+#ifndef MACOS
+#if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \
+ defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)
+#define MACOS
+#endif
+#endif
+
+/* enough people need this for various reasons to include it here */
+#if !defined(MACOS) && !defined(RISCOS)
+#include <sys/types.h>
+#endif
+
+/* This is an attempt to force a single setjmp behaviour on Linux. If
+ * the X config stuff didn't define _BSD_SOURCE we wouldn't need this.
+ */
+#ifdef __linux__
+#ifdef _BSD_SOURCE
+#define _PNG_SAVE_BSD_SOURCE
+#undef _BSD_SOURCE
+#endif
+#ifdef _SETJMP_H
+__png.h__ already includes setjmp.h
+__dont__ include it again
+#endif
+#endif /* __linux__ */
+
+/* include setjmp.h for error handling */
+#include <setjmp.h>
+
+#ifdef __linux__
+#ifdef _PNG_SAVE_BSD_SOURCE
+#define _BSD_SOURCE
+#undef _PNG_SAVE_BSD_SOURCE
+#endif
+#endif /* __linux__ */
+
+#ifdef BSD
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+/* Other defines for things like memory and the like can go here. */
+#ifdef PNG_INTERNAL
+#include <stdlib.h>
+
+/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which
+ * aren't usually used outside the library (as far as I know), so it is
+ * debatable if they should be exported at all. In the future, when it is
+ * possible to have run-time registry of chunk-handling functions, some of
+ * these will be made available again.
+#define PNG_EXTERN extern
+ */
+#define PNG_EXTERN
+
+/* Other defines specific to compilers can go here. Try to keep
+ * them inside an appropriate ifdef/endif pair for portability.
+ */
+
+#if defined(MACOS)
+/* We need to check that <math.h> hasn't already been included earlier
+ * as it seems it doesn't agree with <fp.h>, yet we should really use
+ * <fp.h> if possible.
+ */
+#if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
+#include <fp.h>
+#endif
+#else
+#include <math.h>
+#endif
+
+/* Codewarrior on NT has linking problems without this. */
+#if defined(__MWERKS__) && defined(WIN32)
+#define PNG_ALWAYS_EXTERN
+#endif
+
+/* For some reason, Borland C++ defines memcmp, etc. in mem.h, not
+ * stdlib.h like it should (I think). Or perhaps this is a C++
+ * "feature"?
+ */
+#ifdef __TURBOC__
+#include <mem.h>
+#include "alloc.h"
+#endif
+
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+
+/* This controls how fine the dithering gets. As this allocates
+ * a largish chunk of memory (32K), those who are not as concerned
+ * with dithering quality can decrease some or all of these.
+ */
+#ifndef PNG_DITHER_RED_BITS
+#define PNG_DITHER_RED_BITS 5
+#endif
+#ifndef PNG_DITHER_GREEN_BITS
+#define PNG_DITHER_GREEN_BITS 5
+#endif
+#ifndef PNG_DITHER_BLUE_BITS
+#define PNG_DITHER_BLUE_BITS 5
+#endif
+
+/* This controls how fine the gamma correction becomes when you
+ * are only interested in 8 bits anyway. Increasing this value
+ * results in more memory being used, and more pow() functions
+ * being called to fill in the gamma tables. Don't set this value
+ * less then 8, and even that may not work (I haven't tested it).
+ */
+
+#ifndef PNG_MAX_GAMMA_8
+#define PNG_MAX_GAMMA_8 11
+#endif
+
+/* This controls how much a difference in gamma we can tolerate before
+ * we actually start doing gamma conversion.
+ */
+#ifndef PNG_GAMMA_THRESHOLD
+#define PNG_GAMMA_THRESHOLD 0.05
+#endif
+
+#endif /* PNG_INTERNAL */
+
+/* The following uses const char * instead of char * for error
+ * and warning message functions, so some compilers won't complain.
+ * If you do not want to use const, define PNG_NO_CONST here.
+ */
+
+#ifndef PNG_NO_CONST
+# define PNG_CONST const
+#else
+# define PNG_CONST
+#endif
+
+/* The following defines give you the ability to remove code from the
+ * library that you will not be using. I wish I could figure out how to
+ * automate this, but I can't do that without making it seriously hard
+ * on the users. So if you are not using an ability, change the #define
+ * to and #undef, and that part of the library will not be compiled. If
+ * your linker can't find a function, you may want to make sure the
+ * ability is defined here. Some of these depend upon some others being
+ * defined. I haven't figured out all the interactions here, so you may
+ * have to experiment awhile to get everything to compile. If you are
+ * creating or using a shared library, you probably shouldn't touch this,
+ * as it will affect the size of the structures, and this will cause bad
+ * things to happen if the library and/or application ever change.
+ */
+
+/* Any transformations you will not be using can be undef'ed here */
+
+/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user
+ to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS
+ on the compile line, then pick and choose which ones to define without
+ having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED
+ if you only want to have a png-compliant reader/writer but don't need
+ any of the extra transformations. This saves about 80 kbytes in a
+ typical installation of the library. (PNG_NO_* form added in version
+ 1.0.1c, for consistency)
+ */
+
+
+#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_READ_TRANSFORMS)
+#define PNG_READ_TRANSFORMS_SUPPORTED
+#endif
+#if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_WRITE_TRANSFORMS)
+#define PNG_WRITE_TRANSFORMS_SUPPORTED
+#endif
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+#ifndef PNG_NO_READ_EXPAND
+#define PNG_READ_EXPAND_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_SHIFT
+#define PNG_READ_SHIFT_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_PACK
+#define PNG_READ_PACK_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_BGR
+#define PNG_READ_BGR_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_SWAP
+#define PNG_READ_SWAP_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_PACKSWAP
+#define PNG_READ_PACKSWAP_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_INVERT
+#define PNG_READ_INVERT_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_DITHER
+#define PNG_READ_DITHER_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_BACKGROUND
+#define PNG_READ_BACKGROUND_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_16_TO_8
+#define PNG_READ_16_TO_8_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_FILLER
+#define PNG_READ_FILLER_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_GAMMA
+#define PNG_READ_GAMMA_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_GRAY_TO_RGB
+#define PNG_READ_GRAY_TO_RGB_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_SWAP_ALPHA
+#define PNG_READ_SWAP_ALPHA_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_INVERT_ALPHA
+#define PNG_READ_INVERT_ALPHA_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_STRIP_ALPHA
+#define PNG_READ_STRIP_ALPHA_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_USER_TRANSFORM
+#define PNG_READ_USER_TRANSFORM_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_RGB_TO_GRAY
+#define PNG_READ_RGB_TO_GRAY_SUPPORTED
+#endif
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
+
+#if !defined(PNG_NO_PROGRESSIVE_READ) && \
+ !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */
+#define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */
+#endif /* about interlacing capability! You'll */
+ /* still have interlacing unless you change the following line: */
+#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */
+
+#ifndef PNG_NO_READ_COMPOSITED_NODIV
+#define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel and SGI */
+#endif
+
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
+#ifndef PNG_NO_WRITE_SHIFT
+#define PNG_WRITE_SHIFT_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_PACK
+#define PNG_WRITE_PACK_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_BGR
+#define PNG_WRITE_BGR_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_SWAP
+#define PNG_WRITE_SWAP_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_PACKSWAP
+#define PNG_WRITE_PACKSWAP_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_INVERT
+#define PNG_WRITE_INVERT_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_FILLER
+#define PNG_WRITE_FILLER_SUPPORTED /* This is the same as WRITE_STRIP_ALPHA */
+#endif
+#ifndef PNG_NO_WRITE_SWAP_ALPHA
+#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_INVERT_ALPHA
+#define PNG_WRITE_INVERT_ALPHA_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_USER_TRANSFORM
+#define PNG_WRITE_USER_TRANSFORM_SUPPORTED
+#endif
+#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
+
+#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant
+ encoders, but can cause trouble
+ if left undefined */
+
+#ifndef PNG_NO_WRITE_WEIGHTED_FILTER
+#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+#endif
+
+#ifndef PNG_NO_WRITE_FLUSH
+#define PNG_WRITE_FLUSH_SUPPORTED
+#endif
+
+#ifndef PNG_NO_STDIO
+#define PNG_TIME_RFC1123_SUPPORTED
+#endif
+
+/* This adds extra functions in pngget.c for accessing data from the
+ * info pointer (added in version 0.99)
+ * png_get_image_width()
+ * png_get_image_height()
+ * png_get_bit_depth()
+ * png_get_color_type()
+ * png_get_compression_type()
+ * png_get_filter_type()
+ * png_get_interlace_type()
+ * png_get_pixel_aspect_ratio()
+ * png_get_pixels_per_meter()
+ * png_get_x_offset_pixels()
+ * png_get_y_offset_pixels()
+ * png_get_x_offset_microns()
+ * png_get_y_offset_microns()
+ */
+#ifndef PNG_NO_EASY_ACCESS
+#define PNG_EASY_ACCESS_SUPPORTED
+#endif
+
+/* These are currently experimental features, define them if you want */
+
+/* very little testing */
+/*
+#define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+#define PNG_USER_MEM_SUPPORTED
+*/
+
+/* This is only for PowerPC big-endian and 680x0 systems */
+/* some testing */
+/*
+#define PNG_READ_BIG_ENDIAN_SUPPORTED
+*/
+
+/* These functions are turned off by default, as they will be phased out. */
+/*
+#define PNG_USELESS_TESTS_SUPPORTED
+#define PNG_CORRECT_PALETTE_SUPPORTED
+*/
+
+/* Any chunks you are not interested in, you can undef here. The
+ * ones that allocate memory may be expecially important (hIST,
+ * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info
+ * a bit smaller.
+ */
+
+#if !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_READ_ANCILLARY_CHUNKS)
+#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+#endif
+#if !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS)
+#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+#endif
+
+#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+#ifndef PNG_NO_READ_bKGD
+#define PNG_READ_bKGD_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_cHRM
+#define PNG_READ_cHRM_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_gAMA
+#define PNG_READ_gAMA_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_hIST
+#define PNG_READ_hIST_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_oFFs
+#define PNG_READ_oFFs_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_pCAL
+#define PNG_READ_pCAL_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_pHYs
+#define PNG_READ_pHYs_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sBIT
+#define PNG_READ_sBIT_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sRGB
+#define PNG_READ_sRGB_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tEXt
+#define PNG_READ_tEXt_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tIME
+#define PNG_READ_tIME_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tRNS
+#define PNG_READ_tRNS_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_zTXt
+#define PNG_READ_zTXt_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_OPT_PLTE
+#define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the optional */
+#endif /* PLTE chunk in RGB and RGBA images */
+#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */
+
+#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+#ifndef PNG_NO_WRITE_bKGD
+#define PNG_WRITE_bKGD_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_cHRM
+#define PNG_WRITE_cHRM_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_gAMA
+#define PNG_WRITE_gAMA_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_hIST
+#define PNG_WRITE_hIST_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_oFFs
+#define PNG_WRITE_oFFs_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_pCAL
+#define PNG_WRITE_pCAL_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_pHYs
+#define PNG_WRITE_pHYs_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_sBIT
+#define PNG_WRITE_sBIT_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_sRGB
+#define PNG_WRITE_sRGB_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_tEXt
+#define PNG_WRITE_tEXt_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_tIME
+#define PNG_WRITE_tIME_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_tRNS
+#define PNG_WRITE_tRNS_SUPPORTED
+#endif
+#ifndef PNG_NO_WRITE_zTXt
+#define PNG_WRITE_zTXt_SUPPORTED
+#endif
+#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */
+
+/* need the time information for reading tIME chunks */
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+#include <time.h>
+#endif
+
+/* Some typedefs to get us started. These should be safe on most of the
+ * common platforms. The typedefs should be at least as large as the
+ * numbers suggest (a png_uint_32 must be at least 32 bits long), but they
+ * don't have to be exactly that size. Some compilers dislike passing
+ * unsigned shorts as function parameters, so you may be better off using
+ * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may
+ * want to have unsigned int for png_uint_32 instead of unsigned long.
+ */
+
+typedef unsigned long png_uint_32;
+typedef long png_int_32;
+typedef unsigned short png_uint_16;
+typedef short png_int_16;
+typedef unsigned char png_byte;
+
+/* This is usually size_t. It is typedef'ed just in case you need it to
+ change (I'm not sure if you will or not, so I thought I'd be safe) */
+typedef size_t png_size_t;
+
+/* The following is needed for medium model support. It cannot be in the
+ * PNG_INTERNAL section. Needs modification for other compilers besides
+ * MSC. Model independent support declares all arrays and pointers to be
+ * large using the far keyword. The zlib version used must also support
+ * model independent data. As of version zlib 1.0.4, the necessary changes
+ * have been made in zlib. The USE_FAR_KEYWORD define triggers other
+ * changes that are needed. (Tim Wegner)
+ */
+
+/* Separate compiler dependencies (problem here is that zlib.h always
+ defines FAR. (SJT) */
+#ifdef __BORLANDC__
+#if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__)
+#define LDATA 1
+#else
+#define LDATA 0
+#endif
+
+#if !defined(__WIN32__) && !defined(__FLAT__)
+#define PNG_MAX_MALLOC_64K
+#if (LDATA != 1)
+#ifndef FAR
+#define FAR __far
+#endif
+#define USE_FAR_KEYWORD
+#endif /* LDATA != 1 */
+
+/* Possibly useful for moving data out of default segment.
+ * Uncomment it if you want. Could also define FARDATA as
+ * const if your compiler supports it. (SJT)
+# define FARDATA FAR
+ */
+#endif /* __WIN32__, __FLAT__ */
+
+#endif /* __BORLANDC__ */
+
+
+/* Suggest testing for specific compiler first before testing for
+ * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM,
+ * making reliance oncertain keywords suspect. (SJT)
+ */
+
+/* MSC Medium model */
+#if defined(FAR)
+# if defined(M_I86MM)
+# define USE_FAR_KEYWORD
+# define FARDATA FAR
+# include <dos.h>
+# endif
+#endif
+
+/* SJT: default case */
+#ifndef FAR
+# define FAR
+#endif
+
+/* At this point FAR is always defined */
+#ifndef FARDATA
+#define FARDATA
+#endif
+
+/* Add typedefs for pointers */
+typedef void FAR * png_voidp;
+typedef png_byte FAR * png_bytep;
+typedef png_uint_32 FAR * png_uint_32p;
+typedef png_int_32 FAR * png_int_32p;
+typedef png_uint_16 FAR * png_uint_16p;
+typedef png_int_16 FAR * png_int_16p;
+typedef PNG_CONST char FAR * png_const_charp;
+typedef char FAR * png_charp;
+typedef double FAR * png_doublep;
+
+/* Pointers to pointers; i.e. arrays */
+typedef png_byte FAR * FAR * png_bytepp;
+typedef png_uint_32 FAR * FAR * png_uint_32pp;
+typedef png_int_32 FAR * FAR * png_int_32pp;
+typedef png_uint_16 FAR * FAR * png_uint_16pp;
+typedef png_int_16 FAR * FAR * png_int_16pp;
+typedef PNG_CONST char FAR * FAR * png_const_charpp;
+typedef char FAR * FAR * png_charpp;
+typedef double FAR * FAR * png_doublepp;
+
+/* Pointers to pointers to pointers; i.e. pointer to array */
+typedef char FAR * FAR * FAR * png_charppp;
+
+/* libpng typedefs for types in zlib. If zlib changes
+ * or another compression library is used, then change these.
+ * Eliminates need to change all the source files.
+ */
+typedef charf * png_zcharp;
+typedef charf * FAR * png_zcharpp;
+typedef z_stream FAR * png_zstreamp;
+
+/* allow for compilation as dll under MS Windows */
+#ifdef __WIN32DLL__
+#define PNG_EXPORT(type,symbol) __declspec(dllexport) type symbol
+#endif
+
+/* allow for compilation as dll with BORLAND C++ 5.0 */
+#if defined(__BORLANDC__) && defined(_Windows) && defined(__DLL__)
+# define PNG_EXPORT(type,symbol) type _export symbol
+#endif
+
+/* allow for compilation as shared lib under BeOS */
+#ifdef __BEOSDLL__
+#define PNG_EXPORT(type,symbol) __declspec(export) type symbol
+#endif
+
+#ifndef PNG_EXPORT
+#define PNG_EXPORT(type,symbol) type symbol
+#endif
+
+
+/* User may want to use these so not in PNG_INTERNAL. Any library functions
+ * that are passed far data must be model independent.
+ */
+
+#if defined(USE_FAR_KEYWORD) /* memory model independent fns */
+/* use this to make far-to-near assignments */
+# define CHECK 1
+# define NOCHECK 0
+# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK))
+# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK))
+# define png_strcpy _fstrcpy
+# define png_strlen _fstrlen
+# define png_memcmp _fmemcmp /* SJT: added */
+# define png_memcpy _fmemcpy
+# define png_memset _fmemset
+#else /* use the usual functions */
+# define CVT_PTR(ptr) (ptr)
+# define CVT_PTR_NOCHECK(ptr) (ptr)
+# define png_strcpy strcpy
+# define png_strlen strlen
+# define png_memcmp memcmp /* SJT: added */
+# define png_memcpy memcpy
+# define png_memset memset
+#endif
+/* End of memory model independent support */
+
+/* Just a double check that someone hasn't tried to define something
+ * contradictory.
+ */
+#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K)
+#undef PNG_ZBUF_SIZE
+#define PNG_ZBUF_SIZE 65536
+#endif
+
+#endif /* PNGCONF_H */
+
--- /dev/null
+
+/* pngerror.c - stub functions for i/o and memory allocation
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This file provides a location for all error handling. Users who
+ * need special error handling are expected to write replacement functions
+ * and use png_set_error_fn() to use those functions. See the instructions
+ * at each function.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+static void png_default_error PNGARG((png_structp png_ptr,
+ png_const_charp message));
+static void png_default_warning PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* This function is called whenever there is a fatal error. This function
+ * should not be changed. If there is a need to handle errors differently,
+ * you should supply a replacement error function and use png_set_error_fn()
+ * to replace the error function at run-time.
+ */
+void
+png_error(png_structp png_ptr, png_const_charp message)
+{
+ if (png_ptr->error_fn != NULL)
+ (*(png_ptr->error_fn))(png_ptr, message);
+
+ /* if the following returns or doesn't exist, use the default function,
+ which will not return */
+ png_default_error(png_ptr, message);
+}
+
+/* This function is called whenever there is a non-fatal error. This function
+ * should not be changed. If there is a need to handle warnings differently,
+ * you should supply a replacement warning function and use
+ * png_set_error_fn() to replace the warning function at run-time.
+ */
+void
+png_warning(png_structp png_ptr, png_const_charp message)
+{
+ if (png_ptr->warning_fn != NULL)
+ (*(png_ptr->warning_fn))(png_ptr, message);
+ else
+ png_default_warning(png_ptr, message);
+}
+
+/* These utilities are used internally to build an error message that relates
+ * to the current chunk. The chunk name comes from png_ptr->chunk_name,
+ * this is used to prefix the message. The message is limited in length
+ * to 63 bytes, the name characters are output as hex digits wrapped in []
+ * if the character is invalid.
+ */
+#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
+static PNG_CONST char png_digit[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static void
+png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp message)
+{
+ int iout = 0, iin = 0;
+
+ while (iin < 4) {
+ int c = png_ptr->chunk_name[iin++];
+ if (isnonalpha(c)) {
+ buffer[iout++] = '[';
+ buffer[iout++] = png_digit[(c & 0xf0) >> 4];
+ buffer[iout++] = png_digit[c & 0xf];
+ buffer[iout++] = ']';
+ } else {
+ buffer[iout++] = c;
+ }
+ }
+
+ if (message == NULL)
+ buffer[iout] = 0;
+ else {
+ buffer[iout++] = ':';
+ buffer[iout++] = ' ';
+ png_memcpy(buffer+iout, message, 64);
+ buffer[iout+63] = 0;
+ }
+}
+
+void
+png_chunk_error(png_structp png_ptr, png_const_charp message)
+{
+ char msg[16+64];
+ png_format_buffer(png_ptr, msg, message);
+ png_error(png_ptr, msg);
+}
+
+void
+png_chunk_warning(png_structp png_ptr, png_const_charp message)
+{
+ char msg[16+64];
+ png_format_buffer(png_ptr, msg, message);
+ png_warning(png_ptr, msg);
+}
+
+/* This is the default error handling function. Note that replacements for
+ * this function MUST NOT RETURN, or the program will likely crash. This
+ * function is used by default, or if the program supplies NULL for the
+ * error function pointer in png_set_error_fn().
+ */
+static void
+png_default_error(png_structp png_ptr, png_const_charp message)
+{
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr, "libpng error: %s\n", message);
+#endif
+
+#ifdef USE_FAR_KEYWORD
+ {
+ jmp_buf jmpbuf;
+ png_memcpy(jmpbuf,png_ptr->jmpbuf,sizeof(jmp_buf));
+ longjmp(jmpbuf, 1);
+ }
+#else
+ longjmp(png_ptr->jmpbuf, 1);
+#endif
+}
+
+/* This function is called when there is a warning, but the library thinks
+ * it can continue anyway. Replacement functions don't have to do anything
+ * here if you don't want them to. In the default configuration, png_ptr is
+ * not used, but it is passed in case it may be useful.
+ */
+static void
+png_default_warning(png_structp png_ptr, png_const_charp message)
+{
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr, "libpng warning: %s\n", message);
+#endif
+ if (png_ptr == NULL)
+ return;
+}
+
+/* This function is called when the application wants to use another method
+ * of handling errors and warnings. Note that the error function MUST NOT
+ * return to the calling routine or serious problems will occur. The return
+ * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1)
+ */
+void
+png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warning_fn)
+{
+ png_ptr->error_ptr = error_ptr;
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+}
+
+
+/* This function returns a pointer to the error_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy and png_read_destroy are called.
+ */
+png_voidp
+png_get_error_ptr(png_structp png_ptr)
+{
+ return ((png_voidp)png_ptr->error_ptr);
+}
+
+
+
--- /dev/null
+
+/* pngget.c - retrieval of values from info struct
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+png_uint_32
+png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->valid & flag);
+ else
+ return(0);
+}
+
+png_uint_32
+png_get_rowbytes(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->rowbytes);
+ else
+ return(0);
+}
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+/* easy access to info, added in libpng-0.99 */
+png_uint_32
+png_get_image_width(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->width;
+ }
+ return (0);
+}
+
+png_uint_32
+png_get_image_height(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->height;
+ }
+ return (0);
+}
+
+png_byte
+png_get_bit_depth(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->bit_depth;
+ }
+ return (0);
+}
+
+png_byte
+png_get_color_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->color_type;
+ }
+ return (0);
+}
+
+png_byte
+png_get_filter_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->filter_type;
+ }
+ return (0);
+}
+
+png_byte
+png_get_interlace_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->interlace_type;
+ }
+ return (0);
+}
+
+png_byte
+png_get_compression_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->compression_type;
+ }
+ return (0);
+}
+
+png_uint_32
+png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
+ return (0);
+ else return (info_ptr->x_pixels_per_unit);
+ }
+ else
+#endif
+ return (0);
+}
+
+png_uint_32
+png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
+ return (0);
+ else return (info_ptr->y_pixels_per_unit);
+ }
+ else
+#endif
+ return (0);
+}
+
+png_uint_32
+png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER ||
+ info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit)
+ return (0);
+ else return (info_ptr->x_pixels_per_unit);
+ }
+ else
+#endif
+ return (0);
+}
+
+float
+png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr)
+ {
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_aspect_ratio");
+ if (info_ptr->x_pixels_per_unit == 0)
+ return ((float)0.0);
+ else
+ return ((float)info_ptr->y_pixels_per_unit
+ /(float)info_ptr->x_pixels_per_unit);
+ }
+ else
+#endif
+ return ((float)0.0);
+}
+
+png_uint_32
+png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
+ return (0);
+ else return (info_ptr->x_offset);
+ }
+ else
+#endif
+ return (0);
+}
+
+png_uint_32
+png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
+ return (0);
+ else return (info_ptr->y_offset);
+ }
+ else
+#endif
+ return (0);
+}
+
+png_uint_32
+png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
+ return (0);
+ else return (info_ptr->x_offset);
+ }
+ else
+#endif
+ return (0);
+}
+
+png_uint_32
+png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
+ return (0);
+ else return (info_ptr->y_offset);
+ }
+ else
+#endif
+ return (0);
+}
+
+#ifdef PNG_INCH_CONVERSIONS
+png_uint_32
+png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr)
+ *.03937 +.5)
+}
+
+png_uint_32
+png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr)
+ *.03937 +.5)
+}
+
+png_uint_32
+png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr)
+ *.03937 +.5)
+}
+
+float
+png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((float)png_get_x_offset_microns(png_ptr, info_ptr)
+ *.03937/1000000. +.5)
+}
+
+float
+png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((float)png_get_y_offset_microns(png_ptr, info_ptr)
+ *.03937/1000000. +.5)
+}
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+png_uint_32
+png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+ png_uint_32 retval = 0;
+
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "pHYs");
+ if (res_x != NULL)
+ {
+ *res_x = info_ptr->x_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (res_y != NULL)
+ {
+ *res_y = info_ptr->y_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (unit_type != NULL)
+ {
+ *unit_type = (int)info_ptr->phys_unit_type;
+ retval |= PNG_INFO_pHYs;
+ if(unit_type == 1)
+ {
+ if (res_x != NULL) *res_x = (png_uint_32)(*res_x * 39.37 + .50);
+ if (res_y != NULL) *res_y = (png_uint_32)(*res_y * 39.37 + .50);
+ }
+ }
+ }
+ return (retval);
+}
+#endif /* PNG_READ_pHYs_SUPPORTED */
+#endif /* PNG_INCH_CONVERSIONS */
+
+/* png_get_channels really belongs in here, too, but it's been around longer */
+
+#endif /* PNG_EASY_ACCESS_SUPPORTED */
+
+png_byte
+png_get_channels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->channels);
+ else
+ return (0);
+}
+
+png_bytep
+png_get_signature(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->signature);
+ else
+ return (NULL);
+}
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+png_uint_32
+png_get_bKGD(png_structp png_ptr, png_infop info_ptr,
+ png_color_16p *background)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)
+ && background != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "bKGD");
+ *background = &(info_ptr->background);
+ return (PNG_INFO_bKGD);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+png_uint_32
+png_get_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double *white_x, double *white_y, double *red_x, double *red_y,
+ double *green_x, double *green_y, double *blue_x, double *blue_y)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ {
+ png_debug1(1, "in %s retrieval function\n", "cHRM");
+ if (white_x != NULL)
+ *white_x = (double)info_ptr->x_white;
+ if (white_y != NULL)
+ *white_y = (double)info_ptr->y_white;
+ if (red_x != NULL)
+ *red_x = (double)info_ptr->x_red;
+ if (red_y != NULL)
+ *red_y = (double)info_ptr->y_red;
+ if (green_x != NULL)
+ *green_x = (double)info_ptr->x_green;
+ if (green_y != NULL)
+ *green_y = (double)info_ptr->y_green;
+ if (blue_x != NULL)
+ *blue_x = (double)info_ptr->x_blue;
+ if (blue_y != NULL)
+ *blue_y = (double)info_ptr->y_blue;
+ return (PNG_INFO_cHRM);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+png_uint_32
+png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
+ && file_gamma != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "gAMA");
+ *file_gamma = (double)info_ptr->gamma;
+ return (PNG_INFO_gAMA);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+png_uint_32
+png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)
+ && file_srgb_intent != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "sRGB");
+ *file_srgb_intent = (int)info_ptr->srgb_intent;
+ return (PNG_INFO_sRGB);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+png_uint_32
+png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)
+ && hist != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "hIST");
+ *hist = info_ptr->hist;
+ return (PNG_INFO_hIST);
+ }
+ return (0);
+}
+#endif
+
+png_uint_32
+png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *width, png_uint_32 *height, int *bit_depth,
+ int *color_type, int *interlace_type, int *compression_type,
+ int *filter_type)
+
+{
+ if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL &&
+ bit_depth != NULL && color_type != NULL)
+ {
+ int pixel_depth, channels;
+ png_uint_32 rowbytes_per_pixel;
+
+ png_debug1(1, "in %s retrieval function\n", "IHDR");
+ *width = info_ptr->width;
+ *height = info_ptr->height;
+ *bit_depth = info_ptr->bit_depth;
+ *color_type = info_ptr->color_type;
+ if (compression_type != NULL)
+ *compression_type = info_ptr->compression_type;
+ if (filter_type != NULL)
+ *filter_type = info_ptr->filter_type;
+ if (interlace_type != NULL)
+ *interlace_type = info_ptr->interlace_type;
+
+ /* check for potential overflow of rowbytes */
+ if (*color_type == PNG_COLOR_TYPE_PALETTE)
+ channels = 1;
+ else if (*color_type & PNG_COLOR_MASK_COLOR)
+ channels = 3;
+ else
+ channels = 1;
+ if (*color_type & PNG_COLOR_MASK_ALPHA)
+ channels++;
+ pixel_depth = *bit_depth * channels;
+ rowbytes_per_pixel = (pixel_depth + 7) >> 3;
+ if ((*width > (png_uint_32)2147483647L/rowbytes_per_pixel))
+ {
+ png_warning(png_ptr,
+ "Width too large for libpng to process image data.");
+ }
+ return (1);
+ }
+ return (0);
+}
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+png_uint_32
+png_get_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *offset_x, png_uint_32 *offset_y, int *unit_type)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)
+ && offset_x != NULL && offset_y != NULL && unit_type != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "oFFs");
+ *offset_x = info_ptr->x_offset;
+ *offset_y = info_ptr->y_offset;
+ *unit_type = (int)info_ptr->offset_unit_type;
+ return (PNG_INFO_oFFs);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+png_uint_32
+png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
+ png_charp *units, png_charpp *params)
+{
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL &&
+ purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
+ nparams != NULL && units != NULL && params != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "pCAL");
+ *purpose = info_ptr->pcal_purpose;
+ *X0 = info_ptr->pcal_X0;
+ *X1 = info_ptr->pcal_X1;
+ *type = (int)info_ptr->pcal_type;
+ *nparams = (int)info_ptr->pcal_nparams;
+ *units = info_ptr->pcal_units;
+ *params = info_ptr->pcal_params;
+ return (PNG_INFO_pCAL);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+png_uint_32
+png_get_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+ png_uint_32 retval = 0;
+
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "pHYs");
+ if (res_x != NULL)
+ {
+ *res_x = info_ptr->x_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (res_y != NULL)
+ {
+ *res_y = info_ptr->y_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (unit_type != NULL)
+ {
+ *unit_type = (int)info_ptr->phys_unit_type;
+ retval |= PNG_INFO_pHYs;
+ }
+ }
+ return (retval);
+}
+#endif
+
+png_uint_32
+png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette,
+ int *num_palette)
+{
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_PLTE &&
+ palette != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "PLTE");
+ *palette = info_ptr->palette;
+ *num_palette = info_ptr->num_palette;
+ png_debug1(3, "num_palette = %d\n", *num_palette);
+ return (PNG_INFO_PLTE);
+ }
+ return (0);
+}
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+png_uint_32
+png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit)
+{
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT &&
+ sig_bit != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "sBIT");
+ *sig_bit = &(info_ptr->sig_bit);
+ return (PNG_INFO_sBIT);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+png_uint_32
+png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr,
+ int *num_text)
+{
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)
+ {
+ png_debug1(1, "in %s retrieval function\n",
+ (png_ptr->chunk_name[0] == '\0' ? "text"
+ : (png_const_charp)png_ptr->chunk_name));
+ if (text_ptr != NULL)
+ *text_ptr = info_ptr->text;
+ if (num_text != NULL)
+ *num_text = info_ptr->num_text;
+ return ((png_uint_32)info_ptr->num_text);
+ }
+ return(0);
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+png_uint_32
+png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time)
+{
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME &&
+ mod_time != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "tIME");
+ *mod_time = &(info_ptr->mod_time);
+ return (PNG_INFO_tIME);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+png_uint_32
+png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep *trans, int *num_trans, png_color_16p *trans_values)
+{
+ png_uint_32 retval = 0;
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
+ {
+ png_debug1(1, "in %s retrieval function\n", "tRNS");
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (trans != NULL)
+ {
+ *trans = info_ptr->trans;
+ retval |= PNG_INFO_tRNS;
+ }
+ if (trans_values != NULL)
+ *trans_values = &(info_ptr->trans_values);
+ }
+ else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */
+ {
+ if (trans_values != NULL)
+ {
+ *trans_values = &(info_ptr->trans_values);
+ retval |= PNG_INFO_tRNS;
+ }
+ if(trans != NULL)
+ *trans = NULL;
+ }
+ if(num_trans != NULL)
+ {
+ *num_trans = info_ptr->num_trans;
+ retval |= PNG_INFO_tRNS;
+ }
+ }
+ return (retval);
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+png_byte
+png_get_rgb_to_gray_status (png_structp png_ptr)
+{
+ return png_ptr->rgb_to_gray_status;
+}
+#endif
--- /dev/null
+
+/* pngmem.c - stub functions for memory allocation
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This file provides a location for all memory allocation. Users who
+ * need special memory handling are expected to supply replacement
+ * functions for png_malloc() and png_free(), and to use
+ * png_create_read_struct_2() and png_create_write_struct_2() to
+ * identify the replacement functions.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Borland DOS special memory handler */
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* if you change this, be sure to change the one in png.h also */
+
+/* Allocate memory for a png_struct. The malloc and memset can be replaced
+ by a single call to calloc() if this is thought to improve performance. */
+png_voidp
+png_create_struct(int type)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_struct_2(type, NULL));
+}
+
+/* Alternate version of png_create_struct, for use with user-defined malloc. */
+png_voidp
+png_create_struct_2(int type, png_malloc_ptr malloc_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = sizeof(png_struct);
+ else
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(malloc_fn != NULL)
+ {
+ if ((struct_ptr = (*(malloc_fn))(NULL, size)) != NULL)
+ png_memset(struct_ptr, 0, size);
+ return (struct_ptr);
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+ if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL)
+ {
+ png_memset(struct_ptr, 0, size);
+ }
+ return (struct_ptr);
+}
+
+
+/* Free memory allocated by a png_create_struct() call */
+void
+png_destroy_struct(png_voidp struct_ptr)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2(struct_ptr, (png_free_ptr)NULL);
+}
+
+/* Free memory allocated by a png_create_struct() call */
+void
+png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn)
+{
+#endif
+ if (struct_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(free_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ (*(free_fn))(png_ptr, struct_ptr);
+ struct_ptr = NULL;
+ return;
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+ farfree (struct_ptr);
+ struct_ptr = NULL;
+ }
+}
+
+/* Allocate memory. For reasonable files, size should never exceed
+ * 64K. However, zlib may allocate more then 64K if you don't tell
+ * it not to. See zconf.h and png.h for more information. zlib does
+ * need to allocate exactly 64K, so whatever you call here must
+ * have the ability to do that.
+ *
+ * Borland seems to have a problem in DOS mode for exactly 64K.
+ * It gives you a segment with an offset of 8 (perhaps to store its
+ * memory stuff). zlib doesn't like this at all, so we have to
+ * detect and deal with it. This code should not be needed in
+ * Windows or OS/2 modes, and only in 16 bit mode. This code has
+ * been updated by Alexander Lehmann for version 0.89 to waste less
+ * memory.
+ *
+ * Note that we can't use png_size_t for the "size" declaration,
+ * since on some systems a png_size_t is a 16-bit quantity, and as a
+ * result, we would be truncating potentially larger memory requests
+ * (which should cause a fatal error) and introducing major problems.
+ */
+png_voidp
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+#ifndef PNG_USER_MEM_SUPPORTED
+ png_voidp ret;
+#endif
+ if (png_ptr == NULL || size == 0)
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(png_ptr->malloc_fn != NULL)
+ return ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, size));
+ else
+ return png_malloc_default(png_ptr, size);
+}
+
+png_voidp
+png_malloc_default(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+ if (size == (png_uint_32)65536L)
+ {
+ if (png_ptr->offset_table == NULL)
+ {
+ /* try to see if we need to do any of this fancy stuff */
+ ret = farmalloc(size);
+ if (ret == NULL || ((png_size_t)ret & 0xffff))
+ {
+ int num_blocks;
+ png_uint_32 total_size;
+ png_bytep table;
+ int i;
+ png_byte huge * hptr;
+
+ if (ret != NULL)
+ {
+ farfree(ret);
+ ret = NULL;
+ }
+
+ num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
+ if (num_blocks < 1)
+ num_blocks = 1;
+ if (png_ptr->zlib_mem_level >= 7)
+ num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
+ else
+ num_blocks++;
+
+ total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16;
+
+ table = farmalloc(total_size);
+
+ if (table == NULL)
+ {
+ png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */
+ }
+
+ if ((png_size_t)table & 0xfff0)
+ {
+ png_error(png_ptr, "Farmalloc didn't return normalized pointer");
+ }
+
+ png_ptr->offset_table = table;
+ png_ptr->offset_table_ptr = farmalloc(num_blocks *
+ sizeof (png_bytep));
+
+ if (png_ptr->offset_table_ptr == NULL)
+ {
+ png_error(png_ptr, "Out Of memory.");
+ }
+
+ hptr = (png_byte huge *)table;
+ if ((png_size_t)hptr & 0xf)
+ {
+ hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
+ hptr += 16L;
+ }
+ for (i = 0; i < num_blocks; i++)
+ {
+ png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
+ hptr += (png_uint_32)65536L;
+ }
+
+ png_ptr->offset_table_number = num_blocks;
+ png_ptr->offset_table_count = 0;
+ png_ptr->offset_table_count_free = 0;
+ }
+ }
+
+ if (png_ptr->offset_table_count >= png_ptr->offset_table_number)
+ png_error(png_ptr, "Out of Memory.");
+
+ ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++];
+ }
+ else
+ ret = farmalloc(size);
+
+ if (ret == NULL)
+ {
+ png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */
+ }
+
+ return (ret);
+}
+
+/* free a pointer allocated by png_malloc(). In the default
+ configuration, png_ptr is not used, but is passed in case it
+ is needed. If ptr is NULL, return without taking any action. */
+void
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (png_ptr->free_fn != NULL)
+ {
+ (*(png_ptr->free_fn))(png_ptr, ptr);
+ ptr = NULL;
+ return;
+ }
+ else png_free_default(png_ptr, ptr);
+}
+
+void
+png_free_default(png_structp png_ptr, png_voidp ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ if (png_ptr->offset_table != NULL)
+ {
+ int i;
+
+ for (i = 0; i < png_ptr->offset_table_count; i++)
+ {
+ if (ptr == png_ptr->offset_table_ptr[i])
+ {
+ ptr = NULL;
+ png_ptr->offset_table_count_free++;
+ break;
+ }
+ }
+ if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
+ {
+ farfree(png_ptr->offset_table);
+ farfree(png_ptr->offset_table_ptr);
+ png_ptr->offset_table = NULL;
+ png_ptr->offset_table_ptr = NULL;
+ }
+ }
+
+ if (ptr != NULL)
+ {
+ farfree(ptr);
+ ptr = NULL;
+ }
+}
+
+#else /* Not the Borland DOS special memory handler */
+
+/* Allocate memory for a png_struct or a png_info. The malloc and
+ memset can be replaced by a single call to calloc() if this is thought
+ to improve performance noticably.*/
+png_voidp
+png_create_struct(int type)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_struct_2(type, NULL));
+}
+
+/* Allocate memory for a png_struct or a png_info. The malloc and
+ memset can be replaced by a single call to calloc() if this is thought
+ to improve performance noticably.*/
+png_voidp
+png_create_struct_2(int type, png_malloc_ptr malloc_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = sizeof(png_struct);
+ else
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(malloc_fn != NULL)
+ {
+ if ((struct_ptr = (*(malloc_fn))(NULL, size)) != NULL)
+ png_memset(struct_ptr, 0, size);
+ return (struct_ptr);
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL)
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ if ((struct_ptr = (png_voidp)halloc(size,1)) != NULL)
+# else
+ if ((struct_ptr = (png_voidp)malloc(size)) != NULL)
+# endif
+#endif
+ {
+ png_memset(struct_ptr, 0, size);
+ }
+
+ return (struct_ptr);
+}
+
+
+/* Free memory allocated by a png_create_struct() call */
+void
+png_destroy_struct(png_voidp struct_ptr)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2(struct_ptr, (png_free_ptr)NULL);
+}
+
+/* Free memory allocated by a png_create_struct() call */
+void
+png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ if (struct_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(free_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ (*(free_fn))(png_ptr, struct_ptr);
+ struct_ptr = NULL;
+ return;
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(struct_ptr);
+ struct_ptr = NULL;
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(struct_ptr);
+ struct_ptr = NULL;
+# else
+ free(struct_ptr);
+ struct_ptr = NULL;
+# endif
+#endif
+ }
+}
+
+
+/* Allocate memory. For reasonable files, size should never exceed
+ 64K. However, zlib may allocate more then 64K if you don't tell
+ it not to. See zconf.h and png.h for more information. zlib does
+ need to allocate exactly 64K, so whatever you call here must
+ have the ability to do that. */
+
+png_voidp
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+#ifndef PNG_USER_MEM_SUPPORTED
+ png_voidp ret;
+#endif
+ if (png_ptr == NULL || size == 0)
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(png_ptr->malloc_fn != NULL)
+ return ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, size));
+ else
+ return (png_malloc_default(png_ptr, size));
+}
+png_voidp
+png_malloc_default(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ ret = farmalloc(size);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ ret = halloc(size, 1);
+# else
+ ret = malloc((size_t)size);
+# endif
+#endif
+
+ if (ret == NULL)
+ {
+ png_error(png_ptr, "Out of Memory");
+ }
+
+ return (ret);
+}
+
+/* Free a pointer allocated by png_malloc(). If ptr is NULL, return
+ without taking any action. */
+void
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (png_ptr->free_fn != NULL)
+ {
+ (*(png_ptr->free_fn))(png_ptr, ptr);
+ ptr = NULL;
+ return;
+ }
+ else png_free_default(png_ptr, ptr);
+}
+void
+png_free_default(png_structp png_ptr, png_voidp ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(ptr);
+ ptr = NULL;
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(ptr);
+ ptr = NULL;
+# else
+ free(ptr);
+ ptr = NULL;
+# endif
+#endif
+}
+
+#endif /* Not Borland DOS special memory handler */
+
+png_voidp
+png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2,
+ png_uint_32 length)
+{
+ png_size_t size;
+
+ size = (png_size_t)length;
+ if ((png_uint_32)size != length)
+ png_error(png_ptr,"Overflow in png_memcpy_check.");
+
+ return(png_memcpy (s1, s2, size));
+}
+
+png_voidp
+png_memset_check (png_structp png_ptr, png_voidp s1, int value,
+ png_uint_32 length)
+{
+ png_size_t size;
+
+ size = (png_size_t)length;
+ if ((png_uint_32)size != length)
+ png_error(png_ptr,"Overflow in png_memset_check.");
+
+ return (png_memset (s1, value, size));
+
+}
+
+#ifdef PNG_USER_MEM_SUPPORTED
+/* This function is called when the application wants to use another method
+ * of allocating and freeing memory.
+ */
+void
+png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr
+ malloc_fn, png_free_ptr free_fn)
+{
+ png_ptr->mem_ptr = mem_ptr;
+ png_ptr->malloc_fn = malloc_fn;
+ png_ptr->free_fn = free_fn;
+}
+
+/* This function returns a pointer to the mem_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy and png_read_destroy are called.
+ */
+png_voidp
+png_get_mem_ptr(png_structp png_ptr)
+{
+ return ((png_voidp)png_ptr->mem_ptr);
+}
+#endif /* PNG_USER_MEM_SUPPORTED */
--- /dev/null
+
+/* pngpread.c - read a png file in push mode
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+
+void
+png_process_data(png_structp png_ptr, png_infop info_ptr,
+ png_bytep buffer, png_size_t buffer_size)
+{
+ png_push_restore_buffer(png_ptr, buffer, buffer_size);
+
+ while (png_ptr->buffer_size)
+ {
+ png_process_some_data(png_ptr, info_ptr);
+ }
+}
+
+/* What we do with the incoming data depends on what we were previously
+ * doing before we ran out of data...
+ */
+void
+png_process_some_data(png_structp png_ptr, png_infop info_ptr)
+{
+ switch (png_ptr->process_mode)
+ {
+ case PNG_READ_SIG_MODE:
+ {
+ png_push_read_sig(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_CHUNK_MODE:
+ {
+ png_push_read_chunk(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_IDAT_MODE:
+ {
+ png_push_read_IDAT(png_ptr);
+ break;
+ }
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ case PNG_READ_tEXt_MODE:
+ {
+ png_push_read_tEXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ case PNG_READ_zTXt_MODE:
+ {
+ png_push_read_zTXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+ case PNG_SKIP_MODE:
+ {
+ png_push_crc_finish(png_ptr);
+ break;
+ }
+ default:
+ {
+ png_ptr->buffer_size = 0;
+ break;
+ }
+ }
+}
+
+/* Read any remaining signature bytes from the stream and compare them with
+ * the correct PNG signature. It is possible that this routine is called
+ * with bytes already read from the signature, either because they have been
+ * checked by the calling application, or because of multiple calls to this
+ * routine.
+ */
+void
+png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
+{
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ if (png_ptr->buffer_size < num_to_check)
+ {
+ num_to_check = png_ptr->buffer_size;
+ }
+
+ png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),
+ num_to_check);
+ png_ptr->sig_bytes += num_to_check;
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ else
+ {
+ if (png_ptr->sig_bytes >= 8)
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+ }
+}
+
+void
+png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
+{
+ /* First we make sure we have enough data for the 4 byte chunk name
+ * and the 4 byte chunk length before proceeding with decoding the
+ * chunk data. To fully decode each of these chunks, we also make
+ * sure we have enough data in the buffer for the 4 byte CRC at the
+ * end of every chunk (except IDAT, which is handled separately).
+ */
+ if (!(png_ptr->flags & PNG_FLAG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_32(chunk_length);
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER;
+ }
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ /* If we reach an IDAT chunk, this means we have read all of the
+ * header chunks, and we can start reading the image (or if this
+ * is called after the image has been read - we have an error).
+ */
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ if (png_ptr->push_length == 0)
+ return;
+
+ if (png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ return;
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);
+ png_ptr->process_mode = PNG_READ_DONE_MODE;
+ png_push_have_end(png_ptr, info_ptr);
+ }
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ {
+ png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ {
+ png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+ else
+ {
+ png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+ }
+
+ png_ptr->flags &= ~PNG_FLAG_HAVE_CHUNK_HEADER;
+}
+
+void
+png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
+{
+ png_ptr->process_mode = PNG_SKIP_MODE;
+ png_ptr->skip_length = skip;
+}
+
+void
+png_push_crc_finish(png_structp png_ptr)
+{
+ if (png_ptr->skip_length && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->skip_length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->skip_length)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+}
+
+void
+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
+{
+ png_bytep ptr;
+
+ ptr = buffer;
+ if (png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->save_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size);
+ length -= save_size;
+ ptr += save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->current_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size);
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+}
+
+void
+png_push_save_buffer(png_structp png_ptr)
+{
+ if (png_ptr->save_buffer_size)
+ {
+ if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)
+ {
+ png_size_t i,istop;
+ png_bytep sp;
+ png_bytep dp;
+
+ istop = png_ptr->save_buffer_size;
+ for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;
+ i < istop; i++, sp++, dp++)
+ {
+ *dp = *sp;
+ }
+ }
+ }
+ if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
+ png_ptr->save_buffer_max)
+ {
+ png_size_t new_max;
+ png_bytep old_buffer;
+
+ new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
+ old_buffer = png_ptr->save_buffer;
+ png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)new_max);
+ png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);
+ png_free(png_ptr, old_buffer);
+ png_ptr->save_buffer_max = new_max;
+ }
+ if (png_ptr->current_buffer_size)
+ {
+ png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
+ png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);
+ png_ptr->save_buffer_size += png_ptr->current_buffer_size;
+ png_ptr->current_buffer_size = 0;
+ }
+ png_ptr->save_buffer_ptr = png_ptr->save_buffer;
+ png_ptr->buffer_size = 0;
+}
+
+void
+png_push_restore_buffer(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ png_ptr->current_buffer = buffer;
+ png_ptr->current_buffer_size = buffer_length;
+ png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size;
+ png_ptr->current_buffer_ptr = png_ptr->current_buffer;
+}
+
+void
+png_push_read_IDAT(png_structp png_ptr)
+{
+ if (!(png_ptr->flags & PNG_FLAG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER;
+
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ png_error(png_ptr, "Not enough compressed data");
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ }
+ if (png_ptr->idat_size && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size)
+ {
+ save_size = (png_size_t)png_ptr->idat_size;
+ /* check for overflow */
+ if((png_uint_32)save_size != png_ptr->idat_size)
+ png_error(png_ptr, "save_size overflowed in pngpread");
+ }
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+ png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->idat_size && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size)
+ {
+ save_size = (png_size_t)png_ptr->idat_size;
+ /* check for overflow */
+ if((png_uint_32)save_size != png_ptr->idat_size)
+ png_error(png_ptr, "save_size overflowed in pngpread");
+ }
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+ png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->idat_size)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->flags &= ~PNG_FLAG_HAVE_CHUNK_HEADER;
+ }
+}
+
+void
+png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ int ret;
+
+ if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length)
+ png_error(png_ptr, "Extra compression data");
+
+ png_ptr->zstream.next_in = buffer;
+ png_ptr->zstream.avail_in = (uInt)buffer_length;
+ for(;;)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_in)
+ png_error(png_ptr, "Extra compressed data");
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_push_process_row(png_ptr);
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ else if (ret == Z_BUF_ERROR)
+ break;
+ else if (ret != Z_OK)
+ png_error(png_ptr, "Decompression Error");
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_push_process_row(png_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ }
+ else
+ break;
+ }
+}
+
+void
+png_push_process_row(png_structp png_ptr)
+{
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
+ png_ptr->rowbytes + 1);
+
+ if (png_ptr->transformations)
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+
+ switch (png_ptr->pass)
+ {
+ case 0:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 0; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 1:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 1; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 2)
+ {
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 2:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 3:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 3; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 4)
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 5:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 5; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 6)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 6:
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ if (png_ptr->pass != 6)
+ break;
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ }
+ else
+#endif
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+}
+
+void
+png_read_push_finish_row(png_structp png_ptr)
+{
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset_check(png_ptr, png_ptr->prev_row, 0,
+ png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ png_ptr->pixel_depth + 7) >> 3) + 1;
+
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+
+ } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0);
+ }
+}
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+void
+png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode & PNG_HAVE_IEND)
+ {
+ png_error(png_ptr, "Out of place tEXt");
+ /* to quiet some compiler warnings */
+ if(info_ptr == NULL) return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ png_ptr->skip_length = 0; /* This may not be necessary */
+
+ if (length > (png_uint_32)65535L) /* Can't hold the entire string in memory */
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ png_ptr->skip_length = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_tEXt_MODE;
+}
+
+void
+png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+#if defined(PNG_MAX_MALLOC_64K)
+ if (png_ptr->skip_length)
+ return;
+#endif
+
+ key = png_ptr->current_text;
+ png_ptr->current_text = 0;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ if (text != key + png_ptr->current_text_size)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ }
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+void
+png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode & PNG_HAVE_IEND)
+ {
+ png_error(png_ptr, "Out of place zTXt");
+ /* to quiet some compiler warnings */
+ if(info_ptr == NULL) return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We can't handle zTXt chunks > 64K, since we don't have enough space
+ * to be able to store the uncompressed data. Actually, the threshold
+ * is probably around 32K, but it isn't as definite as 64K is.
+ */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "zTXt chunk too large to fit in memory");
+ png_push_crc_skip(png_ptr, length);
+ return;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_zTXt_MODE;
+}
+
+void
+png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+ int ret;
+ png_size_t text_size, key_size;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+ key = png_ptr->current_text;
+ png_ptr->current_text = 0;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt can't have zero text */
+ if (text == key + png_ptr->current_text_size)
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ png_ptr->zstream.next_in = (png_bytep )text;
+ png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
+ (text - key));
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ key_size = text - key;
+ text_size = 0;
+ text = NULL;
+ ret = Z_STREAM_END;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+ if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out +
+ key_size + 1));
+ png_memcpy(text + key_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_memcpy(text, key, key_size);
+ text_size = key_size + png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = (png_charp)png_malloc(png_ptr, text_size +
+ (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
+ + 1));
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ if (ret != Z_STREAM_END)
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ if (ret == Z_STREAM_END)
+ break;
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (ret != Z_STREAM_END)
+ {
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+
+ png_free(png_ptr, key);
+ key = text;
+ text += key_size;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ }
+}
+#endif
+
+/* This function is called when we haven't found a handler for this
+ * chunk. In the future we will have code here that can handle
+ * user-defined callback functions for unknown chunks before they are
+ * ignored or cause an error. If there isn't a problem with the
+ * chunk itself (ie a bad chunk name or a critical chunk), the chunk
+ * is (currently) silently ignored.
+ */
+void
+png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+ png_chunk_error(png_ptr, "unknown critical chunk");
+ /* to quiet some compiler warnings */
+ if(info_ptr == NULL) return;
+ }
+
+ png_push_crc_skip(png_ptr, length);
+}
+
+void
+png_push_have_info(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->info_fn != NULL)
+ (*(png_ptr->info_fn))(png_ptr, info_ptr);
+}
+
+void
+png_push_have_end(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->end_fn != NULL)
+ (*(png_ptr->end_fn))(png_ptr, info_ptr);
+}
+
+void
+png_push_have_row(png_structp png_ptr, png_bytep row)
+{
+ if (png_ptr->row_fn != NULL)
+ (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,
+ (int)png_ptr->pass);
+}
+
+void
+png_progressive_combine_row (png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row)
+{
+ if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */
+ png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]);
+}
+
+void
+png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn)
+{
+ png_ptr->info_fn = info_fn;
+ png_ptr->row_fn = row_fn;
+ png_ptr->end_fn = end_fn;
+
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+}
+
+png_voidp
+png_get_progressive_ptr(png_structp png_ptr)
+{
+ return png_ptr->io_ptr;
+}
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
--- /dev/null
+
+/* pngread.c - read a PNG file
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This file contains routines that an application calls directly to
+ * read a PNG file or stream.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Create a PNG structure for reading, and allocate any memory needed. */
+png_structp
+png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, NULL, NULL, NULL));
+}
+
+/* Alternate create PNG structure for reading, and allocate any memory needed. */
+png_structp
+png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ png_structp png_ptr;
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+ png_debug(1, "in png_create_read_struct\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
+ (png_malloc_ptr)malloc_fn)) == NULL)
+#else
+ if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
+#endif
+ {
+ return (png_structp)NULL;
+ }
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_destroy_struct(png_ptr);
+ return (png_structp)NULL;
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, NULL, NULL);
+
+ return (png_ptr);
+}
+
+/* Initialize PNG structure for reading, and allocate any memory needed.
+ This interface is deprecated in favour of the png_create_read_struct(),
+ and it will eventually disappear. */
+void
+png_read_init(png_structp png_ptr)
+{
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+
+ png_debug(1, "in png_read_init\n");
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, NULL, NULL);
+}
+
+/* Read the information before the actual image data. This has been
+ * changed in v0.90 to allow reading a file that already has the magic
+ * bytes read from the stream. You can tell libpng how many bytes have
+ * been read from the beginning of the stream (up to the maximum of 8)
+ * via png_set_sig_bytes(), and we will only check the remaining bytes
+ * here. The application can then have access to the signature bytes we
+ * read if it is determined that this isn't a valid PNG file.
+ */
+void
+png_read_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_info\n");
+ /* save jump buffer and error functions */
+ /* If we haven't checked all of the PNG signature bytes, do so now. */
+ if (png_ptr->sig_bytes < 8)
+ {
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
+ png_ptr->sig_bytes = 8;
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ }
+
+ for(;;)
+ {
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
+ /* This should be a binary subdivision search or a hash for
+ * matching the chunk name rather than a linear search.
+ */
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+
+ png_ptr->idat_size = length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ break;
+ }
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ png_handle_sRGB(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ }
+}
+
+/* optional call to update the users info_ptr structure */
+void
+png_read_update_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_update_info\n");
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+ png_read_transform_info(png_ptr, info_ptr);
+}
+
+/* Initialize palette, background, etc, after transformations
+ * are set, but before any reading takes place. This allows
+ * the user to obtain a gamma-corrected palette, for example.
+ * If the user doesn't call this, we will do it ourselves.
+ */
+void
+png_start_read_image(png_structp png_ptr)
+{
+ png_debug(1, "in png_start_read_image\n");
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+}
+
+void
+png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
+{
+ int ret;
+ png_debug2(1, "in png_read_row (row %d, pass %d)\n",
+ png_ptr->row_number, png_ptr->pass);
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ /* check for transforms that have been set but were defined out */
+#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined.");
+#endif
+ }
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* if interlaced and we do not need a new row, combine row and return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 7)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 7) || png_ptr->width < 5)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 7) != 4)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 4))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 3) || png_ptr->width < 3)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 3) != 2)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 2))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 1) || png_ptr->width < 2)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 1))
+ {
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "Invalid attempt to read row data");
+
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ do
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf,
+ (png_size_t)png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_error(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression error");
+
+ } while (png_ptr->zstream.avail_out);
+
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+ {
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+ }
+
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
+ png_ptr->rowbytes + 1);
+
+ if (png_ptr->transformations)
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ if (row != NULL)
+ png_combine_row(png_ptr, row,
+ png_pass_mask[png_ptr->pass]);
+ }
+ else
+#endif
+ {
+ if (row != NULL)
+ png_combine_row(png_ptr, row, 0xff);
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row, 0xff);
+ }
+ png_read_finish_row(png_ptr);
+
+ if (png_ptr->read_row_fn != NULL)
+ (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
+}
+
+/* Read one or more rows of image data. If the image is interlaced,
+ * and png_set_interlace_handling() has been called, the rows need to
+ * contain the contents of the rows from the previous pass. If the
+ * image has alpha or transparency, and png_handle_alpha()[*] has been
+ * called, the rows contents must be initialized to the contents of the
+ * screen.
+ *
+ * "row" holds the actual image, and pixels are placed in it
+ * as they arrive. If the image is displayed after each pass, it will
+ * appear to "sparkle" in. "display_row" can be used to display a
+ * "chunky" progressive image, with finer detail added as it becomes
+ * available. If you do not want this "chunky" display, you may pass
+ * NULL for display_row. If you do not want the sparkle display, and
+ * you have not called png_handle_alpha(), you may pass NULL for rows.
+ * If you have called png_handle_alpha(), and the image has either an
+ * alpha channel or a transparency chunk, you must provide a buffer for
+ * rows. In this case, you do not have to provide a display_row buffer
+ * also, but you may. If the image is not interlaced, or if you have
+ * not called png_set_interlace_handling(), the display_row buffer will
+ * be ignored, so pass NULL to it.
+ *
+ * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.3.
+ */
+
+void
+png_read_rows(png_structp png_ptr, png_bytepp row,
+ png_bytepp display_row, png_uint_32 num_rows)
+{
+ png_uint_32 i;
+ png_bytepp rp;
+ png_bytepp dp;
+
+ png_debug(1, "in png_read_rows\n");
+ /* save jump buffer and error functions */
+ rp = row;
+ dp = display_row;
+ if (rp != NULL && dp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep rptr = *rp++;
+ png_bytep dptr = *dp++;
+
+ png_read_row(png_ptr, rptr, dptr);
+ }
+ else if(rp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep rptr = *rp;
+ png_read_row(png_ptr, rptr, NULL);
+ rp++;
+ }
+ else if(dp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep dptr = *dp;
+ png_read_row(png_ptr, NULL, dptr);
+ dp++;
+ }
+}
+
+/* Read the entire image. If the image has an alpha channel or a tRNS
+ * chunk, and you have called png_handle_alpha()[*], you will need to
+ * initialize the image to the current image that PNG will be overlaying.
+ * We set the num_rows again here, in case it was incorrectly set in
+ * png_read_start_row() by a call to png_read_update_info() or
+ * png_start_read_image() if png_set_interlace_handling() wasn't called
+ * prior to either of these functions like it should have been. You can
+ * only call this function once. If you desire to have an image for
+ * each pass of a interlaced image, use png_read_rows() instead.
+ *
+ * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.3.
+ */
+void
+png_read_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i,image_height;
+ int pass, j;
+ png_bytepp rp;
+
+ png_debug(1, "in png_read_image\n");
+ /* save jump buffer and error functions */
+ pass = png_set_interlace_handling(png_ptr);
+
+ image_height=png_ptr->height;
+ png_ptr->num_rows = image_height; /* Make sure this is set correctly */
+
+ for (j = 0; j < pass; j++)
+ {
+ rp = image;
+ for (i = 0; i < image_height; i++)
+ {
+ png_read_row(png_ptr, *rp, NULL);
+ rp++;
+ }
+ }
+}
+
+/* Read the end of the PNG file. Will not read past the end of the
+ * file, will verify the end is accurate, and will read any comments
+ * or time information at the end of the file, if info is not NULL.
+ */
+void
+png_read_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_debug(1, "in png_read_end\n");
+ /* save jump buffer and error functions */
+ png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
+
+ do
+ {
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ /* Zero length IDATs are legal after the last IDAT has been
+ * read, but not after other chunks have been read.
+ */
+ if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ else
+ png_crc_finish(png_ptr, 0);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ png_handle_sRGB(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ } while (!(png_ptr->mode & PNG_HAVE_IEND));
+}
+
+/* free all memory used by the read */
+void
+png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
+ png_infopp end_info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL, end_info_ptr = NULL;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn = NULL;
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ png_debug(1, "in png_destroy_read_struct\n");
+ /* save jump buffer and error functions */
+ if (png_ptr_ptr != NULL)
+ png_ptr = *png_ptr_ptr;
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (end_info_ptr_ptr != NULL)
+ end_info_ptr = *end_info_ptr_ptr;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+
+ png_read_destroy(png_ptr, info_ptr, end_info_ptr);
+
+ if (info_ptr != NULL)
+ {
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+ png_free(png_ptr, info_ptr->text);
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, free_fn);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (end_info_ptr != NULL)
+ {
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
+ png_free(png_ptr, end_info_ptr->text);
+#endif
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)end_info_ptr, free_fn);
+#else
+ png_destroy_struct((png_voidp)end_info_ptr);
+#endif
+ *end_info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)png_ptr, free_fn);
+#else
+ png_destroy_struct((png_voidp)png_ptr);
+#endif
+ *png_ptr_ptr = (png_structp)NULL;
+ }
+}
+
+/* free all memory used by the read (old method) */
+void
+png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr)
+{
+ jmp_buf tmp_jmp;
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn;
+#endif
+
+ png_debug(1, "in png_read_destroy\n");
+ /* save jump buffer and error functions */
+ if (info_ptr != NULL)
+ png_info_destroy(png_ptr, info_ptr);
+
+ if (end_info_ptr != NULL)
+ png_info_destroy(png_ptr, end_info_ptr);
+
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_free(png_ptr, png_ptr->palette_lookup);
+ png_free(png_ptr, png_ptr->dither_index);
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_table);
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_from_1);
+ png_free(png_ptr, png_ptr->gamma_to_1);
+#endif
+ if (png_ptr->flags & PNG_FLAG_FREE_PALETTE)
+ png_zfree(png_ptr, png_ptr->palette);
+ if (png_ptr->flags & PNG_FLAG_FREE_TRANS)
+ png_free(png_ptr, png_ptr->trans);
+#if defined(PNG_READ_hIST_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_FREE_HIST)
+ png_free(png_ptr, png_ptr->hist);
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->gamma_16_table != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_table[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_table);
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_from_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_from_1);
+ }
+ if (png_ptr->gamma_16_to_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_to_1);
+ }
+#endif
+#endif
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_free(png_ptr, png_ptr->time_buffer);
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+
+ inflateEnd(&png_ptr->zstream);
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_free(png_ptr, png_ptr->save_buffer);
+#endif
+
+ /* Save the important info out of the png_struct, in case it is
+ * being used again.
+ */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr->free_fn = free_fn;
+#endif
+
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+}
+
+void
+png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn)
+{
+ png_ptr->read_row_fn = read_row_fn;
+}
--- /dev/null
+
+/* pngrio.c - functions for data input
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This file provides a location for all input. Users who need
+ * special handling are expected to write a function that has the same
+ * arguments as this and performs a similar function, but that possibly
+ * has a different input method. Note that you shouldn't change this
+ * function, but rather write a replacement function and then make
+ * libpng use it at run time with png_set_read_fn(...).
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Read the data from whatever input you are using. The default routine
+ reads from a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered reads. This should never be asked
+ to read more then 64K on a 16 bit machine. */
+void
+png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_debug1(4,"reading %d bytes\n", length);
+ if (png_ptr->read_data_fn != NULL)
+ (*(png_ptr->read_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL read function");
+}
+
+#if !defined(PNG_NO_STDIO)
+/* This is the function that does the actual reading of data. If you are
+ not reading from a standard C stream, you should create a replacement
+ read_data function and use it at run time with png_set_read_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+#ifdef __VISAGECPP__
+static void _Optlink
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+#else
+static void
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+#endif
+{
+ png_size_t check;
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+ check = (png_size_t)fread(data, (png_size_t)1, length,
+ (FILE *)png_ptr->io_ptr);
+
+ if (check != length)
+ {
+ png_error(png_ptr, "Read Error");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ int check;
+ png_byte *n_data;
+ FILE *io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)n_data == data)
+ {
+ check = fread(n_data, 1, length, io_ptr);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t read, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ read = MIN(NEAR_BUF_SIZE, remaining);
+ err = fread(buf, (png_size_t)1, read, io_ptr);
+ png_memcpy(data, buf, read); /* copy far buffer to near buffer */
+ if(err != read)
+ break;
+ else
+ check += err;
+ data += read;
+ remaining -= read;
+ }
+ while (remaining != 0);
+ }
+ if ((png_uint_32)check != (png_uint_32)length)
+ {
+ png_error(png_ptr, "read Error");
+ }
+}
+#endif
+#endif
+
+/* This function allows the application to supply a new input function
+ for libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png input data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the input functions. May be NULL.
+ read_data_fn - pointer to a new input function that takes as its
+ arguments a pointer to a png_struct, a pointer to
+ a location where input data can be stored, and a 32-bit
+ unsigned int that is the number of bytes to be read.
+ To exit and output any fatal error messages the new write
+ function should call png_error(png_ptr, "Error msg"). */
+void
+png_set_read_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr read_data_fn)
+{
+ png_ptr->io_ptr = io_ptr;
+
+#if !defined(PNG_NO_STDIO)
+ if (read_data_fn != NULL)
+ png_ptr->read_data_fn = read_data_fn;
+ else
+ png_ptr->read_data_fn = png_default_read_data;
+#else
+ png_ptr->read_data_fn = read_data_fn;
+#endif
+
+ /* It is an error to write to a read device */
+ if (png_ptr->write_data_fn != NULL)
+ {
+ png_ptr->write_data_fn = NULL;
+ png_warning(png_ptr,
+ "It's an error to set both read_data_fn and write_data_fn in the ");
+ png_warning(png_ptr,
+ "same structure. Resetting write_data_fn to NULL.");
+ }
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->output_flush_fn = NULL;
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+}
+
--- /dev/null
+
+/* pngrtran.c - transforms the data in a row for PNG readers
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This file contains functions optionally called by an application
+ * in order to tell libpng how to handle data when reading a PNG.
+ * Transformations that are used in both reading and writing are
+ * in pngtrans.c.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(_MSC_VER) && !defined(__MWERKS__)
+#define __VISUALC__ _MSC_VER
+#endif
+#ifdef __VISUALC__
+#ifndef WIN32
+#pragma warning(disable:4135)
+#endif
+#endif
+
+/* Set the action on getting a CRC error for an ancillary or critical chunk. */
+void
+png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
+{
+ png_debug(1, "in png_set_crc_action\n");
+ /* Tell libpng how we react to CRC errors in critical chunks */
+ switch (crit_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
+ PNG_FLAG_CRC_CRITICAL_IGNORE;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
+ png_warning(png_ptr, "Can't discard critical data on CRC error.");
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ break;
+ }
+
+ switch (ancil_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
+ PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* warn/discard data */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ break;
+ }
+}
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* handle alpha and tRNS via a background color */
+void
+png_set_background(png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma)
+{
+ png_debug(1, "in png_set_background\n");
+ if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
+ {
+ png_warning(png_ptr, "Application must supply a known background gamma");
+ return;
+ }
+
+ png_ptr->transformations |= PNG_BACKGROUND;
+ png_memcpy(&(png_ptr->background), background_color, sizeof(png_color_16));
+ png_ptr->background_gamma = (float)background_gamma;
+ png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
+ png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
+
+ /* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA
+ * (in which case need_expand is superfluous anyway), the background color
+ * might actually be gray yet not be flagged as such. This is not a problem
+ * for the current code, which uses PNG_FLAG_BACKGROUND_IS_GRAY only to
+ * decide when to do the png_do_gray_to_rgb() transformation.
+ */
+ if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) ||
+ (!need_expand && background_color->red == background_color->green &&
+ background_color->red == background_color->blue))
+ png_ptr->flags |= PNG_FLAG_BACKGROUND_IS_GRAY;
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip 16 bit depth files to 8 bit depth */
+void
+png_set_strip_16(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_16\n");
+ png_ptr->transformations |= PNG_16_TO_8;
+}
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+void
+png_set_strip_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_alpha\n");
+ png_ptr->transformations |= PNG_STRIP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Dither file to 8 bit. Supply a palette, the current number
+ * of elements in the palette, the maximum number of elements
+ * allowed, and a histogram if possible. If the current number
+ * of colors is greater then the maximum number, the palette will be
+ * modified to fit in the maximum number. "full_dither" indicates
+ * whether we need a dithering cube set up for RGB images, or if we
+ * simply are reducing the number of colors in a paletted image.
+ */
+
+typedef struct png_dsort_struct
+{
+ struct png_dsort_struct FAR * next;
+ png_byte left;
+ png_byte right;
+} png_dsort;
+typedef png_dsort FAR * png_dsortp;
+typedef png_dsort FAR * FAR * png_dsortpp;
+
+void
+png_set_dither(png_structp png_ptr, png_colorp palette,
+ int num_palette, int maximum_colors, png_uint_16p histogram,
+ int full_dither)
+{
+ png_debug(1, "in png_set_dither\n");
+ png_ptr->transformations |= PNG_DITHER;
+
+ if (!full_dither)
+ {
+ int i;
+
+ png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * sizeof (png_byte)));
+ for (i = 0; i < num_palette; i++)
+ png_ptr->dither_index[i] = (png_byte)i;
+ }
+
+ if (num_palette > maximum_colors)
+ {
+ if (histogram != NULL)
+ {
+ /* This is easy enough, just throw out the least used colors.
+ Perhaps not the best solution, but good enough. */
+
+ int i;
+ png_bytep sort;
+
+ /* initialize an array to sort colors */
+ sort = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette
+ * sizeof (png_byte)));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ sort[i] = (png_byte)i;
+
+ /* Find the least used palette entries by starting a
+ bubble sort, and running it until we have sorted
+ out enough colors. Note that we don't care about
+ sorting all the colors, just finding which are
+ least used. */
+
+ for (i = num_palette - 1; i >= maximum_colors; i--)
+ {
+ int done; /* to stop early if the list is pre-sorted */
+ int j;
+
+ done = 1;
+ for (j = 0; j < i; j++)
+ {
+ if (histogram[sort[j]] < histogram[sort[j + 1]])
+ {
+ png_byte t;
+
+ t = sort[j];
+ sort[j] = sort[j + 1];
+ sort[j + 1] = t;
+ done = 0;
+ }
+ }
+ if (done)
+ break;
+ }
+
+ /* swap the palette around, and set up a table, if necessary */
+ if (full_dither)
+ {
+ int j = num_palette;
+
+ /* put all the useful colors within the max, but don't
+ move the others */
+ for (i = 0; i < maximum_colors; i++)
+ {
+ if ((int)sort[i] >= maximum_colors)
+ {
+ do
+ j--;
+ while ((int)sort[j] >= maximum_colors);
+ palette[i] = palette[j];
+ }
+ }
+ }
+ else
+ {
+ int j = num_palette;
+
+ /* move all the used colors inside the max limit, and
+ develop a translation table */
+ for (i = 0; i < maximum_colors; i++)
+ {
+ /* only move the colors we need to */
+ if ((int)sort[i] >= maximum_colors)
+ {
+ png_color tmp_color;
+
+ do
+ j--;
+ while ((int)sort[j] >= maximum_colors);
+
+ tmp_color = palette[j];
+ palette[j] = palette[i];
+ palette[i] = tmp_color;
+ /* indicate where the color went */
+ png_ptr->dither_index[j] = (png_byte)i;
+ png_ptr->dither_index[i] = (png_byte)j;
+ }
+ }
+
+ /* find closest color for those colors we are not using */
+ for (i = 0; i < num_palette; i++)
+ {
+ if ((int)png_ptr->dither_index[i] >= maximum_colors)
+ {
+ int min_d, k, min_k, d_index;
+
+ /* find the closest color to one we threw out */
+ d_index = png_ptr->dither_index[i];
+ min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
+ for (k = 1, min_k = 0; k < maximum_colors; k++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[d_index], palette[k]);
+
+ if (d < min_d)
+ {
+ min_d = d;
+ min_k = k;
+ }
+ }
+ /* point to closest color */
+ png_ptr->dither_index[i] = (png_byte)min_k;
+ }
+ }
+ }
+ png_free(png_ptr, sort);
+ }
+ else
+ {
+ /* This is much harder to do simply (and quickly). Perhaps
+ we need to go through a median cut routine, but those
+ don't always behave themselves with only a few colors
+ as input. So we will just find the closest two colors,
+ and throw out one of them (chosen somewhat randomly).
+ [We don't understand this at all, so if someone wants to
+ work on improving it, be our guest - AED, GRP]
+ */
+ int i;
+ int max_d;
+ int num_new_palette;
+ png_dsortpp hash;
+ png_bytep index_to_palette;
+ /* where the original index currently is in the palette */
+ png_bytep palette_to_index;
+ /* which original index points to this palette color */
+
+ /* initialize palette index arrays */
+ index_to_palette = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * sizeof (png_byte)));
+ palette_to_index = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * sizeof (png_byte)));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ {
+ index_to_palette[i] = (png_byte)i;
+ palette_to_index[i] = (png_byte)i;
+ }
+
+ hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
+ sizeof (png_dsortp)));
+ for (i = 0; i < 769; i++)
+ hash[i] = NULL;
+/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */
+
+ num_new_palette = num_palette;
+
+ /* initial wild guess at how far apart the farthest pixel
+ pair we will be eliminating will be. Larger
+ numbers mean more areas will be allocated, Smaller
+ numbers run the risk of not saving enough data, and
+ having to do this all over again.
+
+ I have not done extensive checking on this number.
+ */
+ max_d = 96;
+
+ while (num_new_palette > maximum_colors)
+ {
+ for (i = 0; i < num_new_palette - 1; i++)
+ {
+ int j;
+
+ for (j = i + 1; j < num_new_palette; j++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[i], palette[j]);
+
+ if (d <= max_d)
+ {
+ png_dsortp t;
+
+ t = (png_dsortp)png_malloc(png_ptr, (png_uint_32)(sizeof
+ (png_dsort)));
+ t->next = hash[d];
+ t->left = (png_byte)i;
+ t->right = (png_byte)j;
+ hash[d] = t;
+ }
+ }
+ }
+
+ for (i = 0; i <= max_d; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p;
+
+ for (p = hash[i]; p; p = p->next)
+ {
+ if ((int)index_to_palette[p->left] < num_new_palette &&
+ (int)index_to_palette[p->right] < num_new_palette)
+ {
+ int j, next_j;
+
+ if (num_new_palette & 1)
+ {
+ j = p->left;
+ next_j = p->right;
+ }
+ else
+ {
+ j = p->right;
+ next_j = p->left;
+ }
+
+ num_new_palette--;
+ palette[index_to_palette[j]] = palette[num_new_palette];
+ if (!full_dither)
+ {
+ int k;
+
+ for (k = 0; k < num_palette; k++)
+ {
+ if (png_ptr->dither_index[k] ==
+ index_to_palette[j])
+ png_ptr->dither_index[k] =
+ index_to_palette[next_j];
+ if ((int)png_ptr->dither_index[k] ==
+ num_new_palette)
+ png_ptr->dither_index[k] =
+ index_to_palette[j];
+ }
+ }
+
+ index_to_palette[palette_to_index[num_new_palette]] =
+ index_to_palette[j];
+ palette_to_index[index_to_palette[j]] =
+ palette_to_index[num_new_palette];
+
+ index_to_palette[j] = (png_byte)num_new_palette;
+ palette_to_index[num_new_palette] = (png_byte)j;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ }
+
+ for (i = 0; i < 769; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p = hash[i];
+ while (p)
+ {
+ png_dsortp t;
+
+ t = p->next;
+ png_free(png_ptr, p);
+ p = t;
+ }
+ }
+ hash[i] = 0;
+ }
+ max_d += 96;
+ }
+ png_free(png_ptr, hash);
+ png_free(png_ptr, palette_to_index);
+ png_free(png_ptr, index_to_palette);
+ }
+ num_palette = maximum_colors;
+ }
+ if (png_ptr->palette == NULL)
+ {
+ png_ptr->palette = palette;
+ }
+ png_ptr->num_palette = (png_uint_16)num_palette;
+
+ if (full_dither)
+ {
+ int i;
+ png_bytep distance;
+ int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
+ PNG_DITHER_BLUE_BITS;
+ int num_red = (1 << PNG_DITHER_RED_BITS);
+ int num_green = (1 << PNG_DITHER_GREEN_BITS);
+ int num_blue = (1 << PNG_DITHER_BLUE_BITS);
+ png_size_t num_entries = ((png_size_t)1 << total_bits);
+
+ png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
+ (png_uint_32)(num_entries * sizeof (png_byte)));
+
+ png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte));
+
+ distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
+ sizeof(png_byte)));
+
+ png_memset(distance, 0xff, num_entries * sizeof(png_byte));
+
+ for (i = 0; i < num_palette; i++)
+ {
+ int ir, ig, ib;
+ int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
+ int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
+ int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
+
+ for (ir = 0; ir < num_red; ir++)
+ {
+ int dr = abs(ir - r);
+ int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
+
+ for (ig = 0; ig < num_green; ig++)
+ {
+ int dg = abs(ig - g);
+ int dt = dr + dg;
+ int dm = ((dr > dg) ? dr : dg);
+ int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
+
+ for (ib = 0; ib < num_blue; ib++)
+ {
+ int d_index = index_g | ib;
+ int db = abs(ib - b);
+ int dmax = ((dm > db) ? dm : db);
+ int d = dmax + dt + db;
+
+ if (d < (int)distance[d_index])
+ {
+ distance[d_index] = (png_byte)d;
+ png_ptr->palette_lookup[d_index] = (png_byte)i;
+ }
+ }
+ }
+ }
+ }
+
+ png_free(png_ptr, distance);
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Transform the image from the file_gamma to the screen_gamma. We
+ * only do transformations on images where the file_gamma and screen_gamma
+ * are not close reciprocals, otherwise it slows things down slightly, and
+ * also needlessly introduces small errors.
+ */
+void
+png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
+{
+ png_debug(1, "in png_set_gamma\n");
+ if (fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD)
+ png_ptr->transformations |= PNG_GAMMA;
+ png_ptr->gamma = (float)file_gamma;
+ png_ptr->screen_gamma = (float)scrn_gamma;
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand paletted images to rgb, expand grayscale images of
+ * less than 8 bit depth to 8 bit depth, and expand tRNS chunks
+ * to alpha channels.
+ */
+void
+png_set_expand(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand\n");
+ png_ptr->transformations |= PNG_EXPAND;
+}
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+void
+png_set_gray_to_rgb(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_gray_to_rgb\n");
+ png_ptr->transformations |= PNG_GRAY_TO_RGB;
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* Convert a RGB image to a grayscale of the same width. This allows us,
+ * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
+ */
+void
+png_set_rgb_to_gray(png_structp png_ptr, int error_action, float red,
+ float green)
+{
+ png_debug(1, "in png_set_rgb_to_gray\n");
+ switch(error_action)
+ {
+ case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
+ break;
+ case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
+ break;
+ case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
+ }
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ png_ptr->transformations |= PNG_EXPAND;
+#else
+ {
+ png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
+ png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
+ }
+#endif
+ {
+ png_byte red_byte = (png_byte)(red*255.0 + 0.5);
+ png_byte green_byte = (png_byte)(green*255.0 + 0.5);
+ if(red < 0.0 || green < 0.0)
+ {
+ red_byte = 54;
+ green_byte = 183;
+ }
+ else if(red_byte + green_byte > 255)
+ {
+ png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
+ red_byte = 54;
+ green_byte = 183;
+ }
+ png_ptr->rgb_to_gray_red_coeff = red_byte;
+ png_ptr->rgb_to_gray_green_coeff = green_byte;
+ png_ptr->rgb_to_gray_blue_coeff = 255 - red_byte - green_byte;
+ }
+}
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+void
+png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
+ read_user_transform_fn)
+{
+ png_debug(1, "in png_set_read_user_transform_fn\n");
+ png_ptr->transformations |= PNG_USER_TRANSFORM;
+ png_ptr->read_user_transform_fn = read_user_transform_fn;
+}
+#endif
+
+/* Initialize everything needed for the read. This includes modifying
+ * the palette.
+ */
+void
+png_init_read_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_init_read_transformations\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if(png_ptr != NULL)
+#endif
+ {
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
+ || defined(PNG_READ_GAMMA_SUPPORTED)
+ int color_type = png_ptr->color_type;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND_EXPAND)
+ {
+ if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
+ {
+ /* expand background chunk. */
+ switch (png_ptr->bit_depth)
+ {
+ case 1:
+ png_ptr->background.gray *= (png_uint_16)0xff;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 2:
+ png_ptr->background.gray *= (png_uint_16)0x55;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 4:
+ png_ptr->background.gray *= (png_uint_16)0x11;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 8:
+ case 16:
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ }
+ }
+ else if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.red =
+ png_ptr->palette[png_ptr->background.index].red;
+ png_ptr->background.green =
+ png_ptr->palette[png_ptr->background.index].green;
+ png_ptr->background.blue =
+ png_ptr->palette[png_ptr->background.index].blue;
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ {
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (!(png_ptr->transformations & PNG_EXPAND))
+#endif
+ {
+ /* invert the alpha channel (in tRNS) unless the pixels are
+ going to be expanded, in which case leave it for later */
+ int i,istop;
+ istop=(int)png_ptr->num_trans;
+ for (i=0; i<istop; i++)
+ png_ptr->trans[i] = 255 - png_ptr->trans[i];
+ }
+ }
+#endif
+
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_ptr->background_1 = png_ptr->background;
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY))
+ {
+ png_build_gamma_table(png_ptr);
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_color back, back_1;
+ png_colorp palette = png_ptr->palette;
+ int num_palette = png_ptr->num_palette;
+ int i;
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g, gs;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->screen_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->screen_gamma);
+ break;
+ default:
+ g = 1.0; /* back_1 */
+ gs = 1.0; /* back */
+ }
+
+ if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+ }
+ else
+ {
+ back.red = (png_byte)(pow(
+ (double)png_ptr->background.red/255, gs) * 255.0 + .5);
+ back.green = (png_byte)(pow(
+ (double)png_ptr->background.green/255, gs) * 255.0 + .5);
+ back.blue = (png_byte)(pow(
+ (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
+ }
+
+ back_1.red = (png_byte)(pow(
+ (double)png_ptr->background.red/255, g) * 255.0 + .5);
+ back_1.green = (png_byte)(pow(
+ (double)png_ptr->background.green/255, g) * 255.0 + .5);
+ back_1.blue = (png_byte)(pow(
+ (double)png_ptr->background.blue/255, g) * 255.0 + .5);
+ }
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else /* if (png_ptr->trans[i] != 0xff) */
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/
+ else
+ /* color_type != PNG_COLOR_TYPE_PALETTE */
+ {
+ double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
+ double g = 1.0;
+ double gs = 1.0;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->screen_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->screen_gamma);
+ break;
+ }
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ /* RGB or RGBA */
+ png_ptr->background_1.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, g) * m + .5);
+ png_ptr->background_1.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, g) * m + .5);
+ png_ptr->background_1.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, g) * m + .5);
+ png_ptr->background.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, gs) * m + .5);
+ png_ptr->background.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, gs) * m + .5);
+ png_ptr->background.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, gs) * m + .5);
+ }
+ else
+ {
+ /* GRAY or GRAY ALPHA */
+ png_ptr->background_1.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, g) * m + .5);
+ png_ptr->background.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, gs) * m + .5);
+ }
+ }
+ }
+ else
+ /* transformation does not include PNG_BACKGROUND */
+#endif
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_colorp palette = png_ptr->palette;
+ int num_palette = png_ptr->num_palette;
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* No GAMMA transformation */
+ if (png_ptr->transformations & PNG_BACKGROUND &&
+ color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int i;
+ int istop = (int)png_ptr->num_trans;
+ png_color back;
+ png_colorp palette = png_ptr->palette;
+
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < istop; i++)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (png_ptr->trans[i] != 0xff)
+ {
+ /* The png_composite() macro is defined in png.h */
+ png_composite(palette[i].red, palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if ((png_ptr->transformations & PNG_SHIFT) &&
+ color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_uint_16 i;
+ png_uint_16 istop = png_ptr->num_palette;
+ int sr = 8 - png_ptr->sig_bit.red;
+ int sg = 8 - png_ptr->sig_bit.green;
+ int sb = 8 - png_ptr->sig_bit.blue;
+
+ if (sr < 0 || sr > 8)
+ sr = 0;
+ if (sg < 0 || sg > 8)
+ sg = 0;
+ if (sb < 0 || sb > 8)
+ sb = 0;
+ for (i = 0; i < istop; i++)
+ {
+ png_ptr->palette[i].red >>= sr;
+ png_ptr->palette[i].green >>= sg;
+ png_ptr->palette[i].blue >>= sb;
+ }
+ }
+#endif
+ }
+}
+
+/* Modify the info structure to reflect the transformations. The
+ * info should be updated so a PNG file could be written with it,
+ * assuming the transformations result in valid PNG data.
+ */
+void
+png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_transform_info\n");
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans)
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ else
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ else
+ {
+ if (png_ptr->num_trans)
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+ if (info_ptr->bit_depth < 8)
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ info_ptr->num_trans = 0;
+ info_ptr->background = png_ptr->background;
+ }
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ info_ptr->gamma = png_ptr->gamma;
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if ((png_ptr->transformations & PNG_16_TO_8) && info_ptr->bit_depth == 16)
+ info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
+ png_ptr->palette_lookup && info_ptr->bit_depth == 8)
+ {
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && info_ptr->bit_depth < 8)
+ info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+ info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
+#endif
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_STRIP_ALPHA)
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+#endif
+
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
+ if (png_ptr->transformations & PNG_FILLER &&
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+ info_ptr->color_type == PNG_COLOR_TYPE_GRAY))
+ ++info_ptr->channels;
+#endif
+
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
+ info_ptr->bit_depth);
+ info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
+}
+
+/* Transform the row. The order of transformations is significant,
+ * and is very touchy. If you add a transformation, take care to
+ * decide how it fits in with the other transformations here.
+ */
+void
+png_do_read_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_read_transformations\n");
+#if !defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (png_ptr->row_buf == NULL)
+ {
+#if !defined(PNG_NO_STDIO)
+ char msg[50];
+
+ sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
+ png_ptr->pass);
+ png_error(png_ptr, msg);
+#else
+ png_error(png_ptr, "NULL row buffer");
+#endif
+ }
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
+ }
+ else
+ {
+ if (png_ptr->num_trans)
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values));
+ else
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ NULL);
+ }
+ }
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_STRIP_ALPHA)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ PNG_FLAG_FILLER_AFTER);
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+ {
+ int rgb_error =
+ png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
+ if(rgb_error)
+ {
+ png_ptr->rgb_to_gray_status=1;
+ if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN)
+ png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+ if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR)
+ png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+ }
+ }
+#endif
+
+/*
+From Andreas Dilger e-mail to png-implement, 26 March 1998:
+
+ In most cases, the "simple transparency" should be done prior to doing
+ gray-to-RGB, or you will have to test 3x as many bytes to check if a
+ pixel is transparent. You would also need to make sure that the
+ transparency information is upgraded to RGB.
+
+ To summarize, the current flow is:
+ - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
+ with background "in place" if transparent,
+ convert to RGB if necessary
+ - Gray + alpha -> composite with gray background and remove alpha bytes,
+ convert to RGB if necessary
+
+ To support RGB backgrounds for gray images we need:
+ - Gray + simple transparency -> convert to RGB + simple transparency, compare
+ 3 or 6 bytes and composite with background
+ "in place" if transparent (3x compare/pixel
+ compared to doing composite with gray bkgrnd)
+ - Gray + alpha -> convert to RGB + alpha, composite with background and
+ remove alpha bytes (3x float operations/pixel
+ compared with composite on gray background)
+
+ Greg's change will do this. The reason it wasn't done before is for
+ performance, as this increases the per-pixel operations. If we would check
+ in advance if the background was gray or RGB, and position the gray-to-RGB
+ transform appropriately, then it would save a lot of work/time.
+ */
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ /* if gray -> RGB, do so now only if background is non-gray; else do later
+ * for performance reasons */
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB &&
+ !(png_ptr->flags & PNG_FLAG_BACKGROUND_IS_GRAY))
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if ((png_ptr->transformations & PNG_BACKGROUND) &&
+ ((png_ptr->num_trans != 0 ) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
+ png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values), &(png_ptr->background),
+ &(png_ptr->background_1),
+ png_ptr->gamma_table, png_ptr->gamma_from_1,
+ png_ptr->gamma_to_1, png_ptr->gamma_16_table,
+ png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
+ png_ptr->gamma_shift);
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if ((png_ptr->transformations & PNG_GAMMA) &&
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ !((png_ptr->transformations & PNG_BACKGROUND) &&
+ ((png_ptr->num_trans != 0) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
+#endif
+ (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
+ png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->gamma_table, png_ptr->gamma_16_table,
+ png_ptr->gamma_shift);
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if (png_ptr->transformations & PNG_16_TO_8)
+ png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette_lookup, png_ptr->dither_index);
+ if(png_ptr->row_info.rowbytes == (png_uint_32)0)
+ png_error(png_ptr, "png_do_dither returned rowbytes=0");
+ }
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ /* if gray -> RGB, do so now only if we did not do so above */
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB &&
+ png_ptr->flags & PNG_FLAG_BACKGROUND_IS_GRAY)
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->filler, png_ptr->flags);
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ if (png_ptr->transformations & PNG_USER_TRANSFORM)
+ if(png_ptr->read_user_transform_fn != NULL)
+ (*(png_ptr->read_user_transform_fn)) /* user read transform function */
+ (png_ptr, /* png_ptr */
+ &(png_ptr->row_info), /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* png_uint_32 rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
+#endif
+
+}
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
+ * without changing the actual values. Thus, if you had a row with
+ * a bit depth of 1, you would end up with bytes that only contained
+ * the numbers 0 or 1. If you would rather they contain 0 and 255, use
+ * png_do_shift() after this.
+ */
+void
+png_do_unpack(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_unpack\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
+#else
+ if (row_info->bit_depth < 8)
+#endif
+ {
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = 7 - (int)((row_width + 7) & 7);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x1);
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = (int)((3 - ((row_width + 3) & 3)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x3);
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = (int)((1 - ((row_width + 1) & 1)) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0xf);
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = row_width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+/* Reverse the effects of png_do_shift. This routine merely shifts the
+ * pixels back to their significant bits values. Thus, if you have
+ * a row of bit depth 8, but only 5 are significant, this will shift
+ * the values back to 0 through 31.
+ */
+void
+png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
+{
+ png_debug(1, "in png_do_unshift\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL && sig_bits != NULL &&
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift[4];
+ int channels = 0;
+ int c;
+ png_uint_16 value = 0;
+ png_uint_32 row_width = row_info->width;
+
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->red;
+ shift[channels++] = row_info->bit_depth - sig_bits->green;
+ shift[channels++] = row_info->bit_depth - sig_bits->blue;
+ }
+ else
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->gray;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->alpha;
+ }
+
+ for (c = 0; c < channels; c++)
+ {
+ if (shift[c] <= 0)
+ shift[c] = 0;
+ else
+ value = 1;
+ }
+
+ if (!value)
+ return;
+
+ switch (row_info->bit_depth)
+ {
+ case 2:
+ {
+ png_bytep bp;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (bp = row, i = 0; i < istop; i++)
+ {
+ *bp >>= 1;
+ *bp++ &= 0x55;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_byte mask = (png_byte)(((int)0xf0 >> shift[0]) & (int)0xf0) |
+ (png_byte)((int)0xf >> shift[0]);
+
+ for (i = 0; i < istop; i++)
+ {
+ *bp >>= shift[0];
+ *bp++ &= mask;
+ }
+ break;
+ }
+ case 8:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_width * channels;
+
+ for (i = 0; i < istop; i++)
+ {
+ *bp++ >>= shift[i%channels];
+ }
+ break;
+ }
+ case 16:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_width;
+
+ for (i = 0; i < istop; i++)
+ {
+ value = (png_uint_16)((*bp << 8) + *(bp + 1));
+ value >>= shift[i%channels];
+ *bp++ = (png_byte)(value >> 8);
+ *bp++ = (png_byte)(value & 0xff);
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* chop rows of bit depth 16 down to 8 */
+void
+png_do_chop(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_chop\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
+#else
+ if (row_info->bit_depth == 16)
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->width * row_info->channels;
+
+ for (i = 0; i<istop; i++, sp += 2, dp++)
+ {
+#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
+ /* This does a more accurate scaling of the 16-bit color
+ * value, rather than a simple low-byte truncation.
+ *
+ * What the ideal calculation should be:
+ * *dp = (((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
+ *
+ * GRR: no, I think this is what it really should be:
+ * *dp = (((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
+ *
+ * GRR: here's the exact calculation with shifts:
+ * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
+ * *dp = (temp - (temp >> 8)) >> 8;
+ *
+ * Approximate calculation with shift/add instead of multiply/divide:
+ * *dp = ((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
+ *
+ * What we actually do to avoid extra shifting and conversion:
+ */
+
+ *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
+#else
+ /* Simply discard the low order byte */
+ *dp = *sp;
+#endif
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = row_info->width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+void
+png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from RGBA to ARGB */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from RRGGBBAA to AARRGGBB */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from GA to AG */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from GGAA to AAGG */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+void
+png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_invert_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This inverts the alpha channel in RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = 255 - *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ }
+ /* This inverts the alpha channel in RRGGBBAA */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = 255 - *(--sp);
+ *(--dp) = 255 - *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This inverts the alpha channel in GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = 255 - *(--sp);
+ *(--dp) = *(--sp);
+ }
+ }
+ /* This inverts the alpha channel in GGAA */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = 255 - *(--sp);
+ *(--dp) = 255 - *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+/* Add filler channel if we have RGB color */
+void
+png_do_read_filler(png_row_infop row_info, png_bytep row,
+ png_uint_32 filler, png_uint_32 flags)
+{
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
+ png_byte lo_filler = (png_byte)(filler & 0xff);
+
+ png_debug(1, "in png_do_read_filler\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if(row_info->bit_depth == 8)
+ {
+ /* This changes the data from G to GX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = lo_filler;
+ row_info->channels = 2;
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ /* This changes the data from G to XG */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 2;
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ }
+ else if(row_info->bit_depth == 16)
+ {
+ /* This changes the data from GG to GGXX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ row_info->channels = 2;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 2;
+ }
+ /* This changes the data from GG to XXGG */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 2;
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ }
+ } /* COLOR_TYPE == GRAY */
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if(row_info->bit_depth == 8)
+ {
+ /* This changes the data from RGB to RGBX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = lo_filler;
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ /* This changes the data from RGB to XRGB */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ }
+ else if(row_info->bit_depth == 16)
+ {
+ /* This changes the data from RRGGBB to RRGGBBXX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ row_info->channels = 4;
+ row_info->pixel_depth = 64;
+ row_info->rowbytes = row_width * 4;
+ }
+ /* This changes the data from RRGGBB to XXRRGGBB */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 64;
+ row_info->rowbytes = row_width * 4;
+ }
+ }
+ } /* COLOR_TYPE == RGB */
+}
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* expand grayscale files to RGB, with or without alpha */
+void
+png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
+{
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ png_debug(1, "in png_do_gray_to_rgb\n");
+ if (row_info->bit_depth >= 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ !(row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + (png_size_t)row_width - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ sp--;
+ }
+ }
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 4;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ sp--;
+ sp--;
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ sp--;
+ }
+ }
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 4 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 4;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ sp--;
+ sp--;
+ }
+ }
+ }
+ row_info->channels += (png_byte)2;
+ row_info->color_type |= PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = ((row_width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* reduce RGB files to grayscale, with or without alpha
+ * using the equation given in Poynton's ColorFAQ at
+ * <http://www.inforamp.net/~poynton/>
+ * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
+ *
+ * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+ *
+ * We approximate this with
+ *
+ * Y = 0.211 * R + 0.715 * G + 0.074 * B
+ *
+ * which can be expressed with integers as
+ *
+ * Y = (54 * R + 183 * G + 19 * B)/256
+ *
+ * The calculation is to be done in a linear colorspace.
+ *
+ * Other integer coefficents can be used via png_set_rgb_to_gray().
+ */
+int
+png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
+
+{
+ png_uint_32 i;
+
+ png_uint_32 row_width = row_info->width;
+ int rgb_error = 0;
+
+ png_debug(1, "in png_do_rgb_to_gray\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ png_byte rc = png_ptr->rgb_to_gray_red_coeff;
+ png_byte gc = png_ptr->rgb_to_gray_green_coeff;
+ png_byte bc = png_ptr->rgb_to_gray_blue_coeff;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = png_ptr->gamma_to_1[*(sp++)];
+ png_byte green = png_ptr->gamma_to_1[*(sp++)];
+ png_byte blue = png_ptr->gamma_to_1[*(sp++)];
+ if(red != green || red != blue)
+ {
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1[
+ (rc*red+gc*green+bc*blue)>>8];
+ }
+ else
+ *(dp++) = *(sp-1);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+ if(red != green || red != blue)
+ {
+ rgb_error |= 1;
+ *(dp++) = (rc*red+gc*green+bc*blue)>>8;
+ }
+ else
+ *(dp++) = *(sp-1);
+ }
+ }
+ }
+
+ else /* RGB bit_depth == 16 */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_to_1 != NULL &&
+ png_ptr->gamma_16_from_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, w;
+
+ red = ((*(sp))<<8) | *(sp+1); sp+=2;
+ green = ((*(sp))<<8) | *(sp+1); sp+=2;
+ blue = ((*(sp))<<8) | *(sp+1); sp+=2;
+
+ if(red == green && red == blue)
+ w = red;
+ else
+ {
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
+ png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
+ png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (rc * red_1 + gc * green_1
+ + bc * blue_1)>>8;
+ w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (w>>8) & 0xff;
+ *(dp++) = w & 0xff;
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, gray16;
+
+ red = ((*(sp))<<8) | *(sp+1); sp+=2;
+ green = ((*(sp))<<8) | *(sp+1); sp+=2;
+ blue = ((*(sp))<<8) | *(sp+1); sp+=2;
+
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ gray16 = (rc * red + gc * green + bc * blue)>>8;
+ *(dp++) = (gray16>>8) & 0xff;
+ *(dp++) = gray16 & 0xff;
+ }
+ }
+ }
+ }
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = png_ptr->gamma_to_1[*(sp++)];
+ png_byte green = png_ptr->gamma_to_1[*(sp++)];
+ png_byte blue = png_ptr->gamma_to_1[*(sp++)];
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1
+ [(rc*red + gc*green + bc*blue)>>8];
+ *(dp++) = *(sp++); /* alpha */
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ *(dp++) = (gc*red + gc*green + bc*blue)>>8;
+ *(dp++) = *(sp++); /* alpha */
+ }
+ }
+ }
+ else /* RGBA bit_depth == 16 */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_to_1 != NULL &&
+ png_ptr->gamma_16_from_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, w;
+
+ red = ((*(sp))<<8) | *(sp+1); sp+=2;
+ green = ((*(sp))<<8) | *(sp+1); sp+=2;
+ blue = ((*(sp))<<8) | *(sp+1); sp+=2;
+
+ if(red == green && red == blue)
+ w = red;
+ else
+ {
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
+ png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
+ png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (rc * red_1 + gc * green_1
+ + bc * blue_1)>>8;
+ w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (w>>8) & 0xff;
+ *(dp++) = w & 0xff;
+ *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, gray16;
+ red = (*(sp)<<8) | *(sp+1); sp+=2;
+ green = (*(sp)<<8) | *(sp+1); sp+=2;
+ blue = (*(sp)<<8) | *(sp+1); sp+=2;
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ gray16 = (rc * red + gc * green + bc * blue)>>8;
+ *(dp++) = (gray16>>8) & 0xff;
+ *(dp++) = gray16 & 0xff;
+ *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
+ }
+ }
+ }
+ }
+ row_info->channels -= (png_byte)2;
+ row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = ((row_width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+ return rgb_error;
+}
+#endif
+
+/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
+ * large of png_color. This lets grayscale images be treated as
+ * paletted. Most useful for gamma correction and simplification
+ * of code.
+ */
+void
+png_build_grayscale_palette(int bit_depth, png_colorp palette)
+{
+ int num_palette;
+ int color_inc;
+ int i;
+ int v;
+
+ png_debug(1, "in png_do_build_grayscale_palette\n");
+ if (palette == NULL)
+ return;
+
+ switch (bit_depth)
+ {
+ case 1:
+ num_palette = 2;
+ color_inc = 0xff;
+ break;
+ case 2:
+ num_palette = 4;
+ color_inc = 0x55;
+ break;
+ case 4:
+ num_palette = 16;
+ color_inc = 0x11;
+ break;
+ case 8:
+ num_palette = 256;
+ color_inc = 1;
+ break;
+ default:
+ num_palette = 0;
+ color_inc = 0;
+ break;
+ }
+
+ for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
+ {
+ palette[i].red = (png_byte)v;
+ palette[i].green = (png_byte)v;
+ palette[i].blue = (png_byte)v;
+ }
+}
+
+/* This function is currently unused. Do we really need it? */
+#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
+void
+png_correct_palette(png_structp png_ptr, png_colorp palette,
+ int num_palette)
+{
+ png_debug(1, "in png_correct_palette\n");
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
+ {
+ png_color back, back_1;
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g;
+
+ g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
+ fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = png_ptr->background.red;
+ back.green = png_ptr->background.green;
+ back.blue = png_ptr->background.blue;
+ }
+ else
+ {
+ back.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ g = 1.0 / png_ptr->background_gamma;
+
+ back_1.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back_1.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back_1.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_uint_32 i;
+
+ for (i = 0; i < (png_uint_32)num_palette; i++)
+ {
+ if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i] = back;
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ }
+ else
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_color back;
+
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < (int)png_ptr->num_trans; i++)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i].red = back.red;
+ palette[i].green = back.green;
+ palette[i].blue = back.blue;
+ }
+ else if (png_ptr->trans[i] != 0xff)
+ {
+ png_composite(palette[i].red, png_ptr->palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, png_ptr->palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, png_ptr->palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+ else /* assume grayscale palette (what else could it be?) */
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i].red = (png_byte)png_ptr->background.red;
+ palette[i].green = (png_byte)png_ptr->background.green;
+ palette[i].blue = (png_byte)png_ptr->background.blue;
+ }
+ }
+ }
+ }
+#endif
+}
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Replace any alpha or transparency with the supplied background color.
+ * "background" is already in the screen gamma, while "background_1" is
+ * at a gamma of 1.0. Paletted files have already been taken care of.
+ */
+void
+png_do_background(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background,
+ png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+ int shift;
+
+ png_debug(1, "in png_do_background\n");
+ if (background != NULL &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
+ (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row;
+ shift = 7;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x1)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 7;
+ sp++;
+ }
+ else
+ shift--;
+ }
+ break;
+ }
+ case 2:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x3)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ else
+ {
+ png_byte p = (*sp >> shift) & 0x3;
+ png_byte g = (gamma_table [p | (p << 2) | (p << 4) |
+ (p << 6)] >> 6) & 0x3;
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(g << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x3)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0xf)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ else
+ {
+ png_byte p = (*sp >> shift) & 0xf;
+ png_byte g = (gamma_table[p | (p << 4)] >> 4) & 0xf;
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(g << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0xf)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ }
+ break;
+ }
+ case 8:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ if (v == trans_values->gray)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ if (v == trans_values->gray)
+ {
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ *(sp + 1) = gamma_table[*(sp + 1)];
+ *(sp + 2) = gamma_table[*(sp + 2)];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ png_uint_16 g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ png_uint_16 b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ png_uint_16 g = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ png_uint_16 b = ((png_uint_16)(*(sp + 4)) << 8) + *(sp + 5);
+
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 2, dp++)
+ {
+ png_uint_16 a = *(sp + 1);
+
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->gray);
+ *dp = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 2, dp++)
+ {
+ png_byte a = *(sp + 1);
+
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background_1->gray);
+ }
+ }
+ }
+ }
+ else /* if (png_ptr->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ png_uint_16 g, v, w;
+
+ g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(v, g, a, background_1->gray);
+ w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
+ *dp = (png_byte)((w >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(w & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a = ((png_uint_16)(*(sp + 2)) << 8) + *(sp + 3);
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ png_uint_16 g, v;
+
+ g = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ png_composite_16(v, g, a, background_1->gray);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ *(dp + 1) = gamma_table[*(sp + 1)];
+ *(dp + 2) = gamma_table[*(sp + 2)];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->red);
+ *dp = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 1)];
+ png_composite(w, v, a, background_1->green);
+ *(dp + 1) = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 2)];
+ png_composite(w, v, a, background_1->blue);
+ *(dp + 2) = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ *(dp + 1) = *(sp + 1);
+ *(dp + 2) = *(sp + 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background->red);
+ png_composite(*(dp + 1), *(sp + 1), a,
+ background->green);
+ png_composite(*(dp + 2), *(sp + 2), a,
+ background->blue);
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v, w, x;
+
+ v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(w, v, a, background->red);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *dp = (png_byte)((x >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ png_composite_16(w, v, a, background->green);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *(dp + 2) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ png_composite_16(w, v, a, background->blue);
+ x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
+ *(dp + 4) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(x & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 6);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v;
+
+ png_uint_16 r = ((png_uint_16)(*sp) << 8) + *(sp + 1);
+ png_uint_16 g = ((png_uint_16)(*(sp + 2)) << 8)
+ + *(sp + 3);
+ png_uint_16 b = ((png_uint_16)(*(sp + 4)) << 8)
+ + *(sp + 5);
+
+ png_composite_16(v, r, a, background->red);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ png_composite_16(v, g, a, background->green);
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ png_composite_16(v, b, a, background->blue);
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ row_info->channels--;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = ((row_width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Gamma correct the image, avoiding the alpha channel. Make sure
+ * you do this after you deal with the transparency issue on grayscale
+ * or rgb images. If your bit depth is 8, use gamma_table, if it
+ * is 16, use gamma_16_table and gamma_shift. Build these with
+ * build_gamma_table().
+ */
+void
+png_do_gamma(png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift)
+{
+ png_bytep sp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_gamma\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
+ (row_info->bit_depth == 16 && gamma_16_table != NULL)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp += 2;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ if (row_info->bit_depth == 2)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i += 4)
+ {
+ int a = *sp & 0xc0;
+ int b = *sp & 0x30;
+ int c = *sp & 0x0c;
+ int d = *sp & 0x03;
+
+ *sp = ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
+ ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
+ ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
+ ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) );
+ sp++;
+ }
+ }
+ if (row_info->bit_depth == 4)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i += 2)
+ {
+ int msb = *sp & 0xf0;
+ int lsb = *sp & 0x0f;
+
+ *sp = (((int)gamma_table[msb | (msb >> 4)]) & 0xf0) |
+ (((int)gamma_table[(lsb << 4) | lsb]) >> 4);
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expands a palette row to an rgb or rgba row depending
+ * upon whether you supply trans and num_trans.
+ */
+void
+png_do_expand_palette(png_row_infop row_info, png_bytep row,
+ png_colorp palette, png_bytep trans, int num_trans)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_expand_palette\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 3);
+ dp = row + (png_size_t)row_width - 1;
+ shift = 7 - (int)((row_width + 7) & 7);
+ for (i = 0; i < row_width; i++)
+ {
+ if ((*sp >> shift) & 0x1)
+ *dp = 1;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 2);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((3 - ((row_width + 3) & 3)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp = (png_byte)value;
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 1);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((row_width & 1) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp = (png_byte)value;
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+ switch (row_info->bit_depth)
+ {
+ case 8:
+ {
+ if (trans != NULL)
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width << 2) - 1;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if ((int)(*sp) >= num_trans)
+ *dp-- = 0xff;
+ else
+ *dp-- = trans[*sp];
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ row_info->color_type = 6;
+ row_info->channels = 4;
+ }
+ else
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width * 3) - 1;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_width * 3;
+ row_info->color_type = 2;
+ row_info->channels = 3;
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* If the bit depth < 8, it is expanded to 8. Also, if the
+ * transparency value is supplied, an alpha channel is built.
+ */
+void
+png_do_expand(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_value)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_expand\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_uint_16 gray = trans_value ? trans_value->gray : 0;
+
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ gray *= 0xff;
+ sp = row + (png_size_t)((row_width - 1) >> 3);
+ dp = row + (png_size_t)row_width - 1;
+ shift = 7 - (int)((row_width + 7) & 7);
+ for (i = 0; i < row_width; i++)
+ {
+ if ((*sp >> shift) & 0x1)
+ *dp = 0xff;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ gray *= 0x55;
+ sp = row + (png_size_t)((row_width - 1) >> 2);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((3 - ((row_width + 3) & 3)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp = (png_byte)(value | (value << 2) | (value << 4) |
+ (value << 6));
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ gray *= 0x11;
+ sp = row + (png_size_t)((row_width - 1) >> 1);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((1 - ((row_width + 1) & 1)) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp = (png_byte)(value | (value << 4));
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+
+ if (trans_value != NULL)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width << 1) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*sp == gray)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (row_info->rowbytes << 1) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (((png_uint_16)*(sp) |
+ ((png_uint_16)*(sp - 1) << 8)) == gray)
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ row_info->channels = 2;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth) >> 3);
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row + (png_size_t)row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_width << 2) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*(sp - 2) == trans_value->red &&
+ *(sp - 1) == trans_value->green &&
+ *(sp - 0) == trans_value->blue)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_width << 3) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((((png_uint_16)*(sp - 4) |
+ ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
+ (((png_uint_16)*(sp - 2) |
+ ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
+ (((png_uint_16)*(sp - 0) |
+ ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ row_info->channels = 4;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth) >> 3);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+void
+png_do_dither(png_row_infop row_info, png_bytep row,
+ png_bytep palette_lookup, png_bytep dither_lookup)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_dither\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ palette_lookup && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+
+ /* this looks real messy, but the compiler will reduce
+ it down to a reasonable formula. For example, with
+ 5 bits per color, we get:
+ p = (((r >> 3) & 0x1f) << 10) |
+ (((g >> 3) & 0x1f) << 5) |
+ ((b >> 3) & 0x1f);
+ */
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
+ palette_lookup != NULL && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+ sp++;
+
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+ dither_lookup && row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ *sp = dither_lookup[*sp];
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+static int png_gamma_shift[] =
+ {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
+
+/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
+ * tables, we don't make a full table if we are reducing to 8-bit in
+ * the future. Note also how the gamma_16 tables are segmented so that
+ * we don't need to allocate > 64K chunks for a full 16-bit table.
+ */
+void
+png_build_gamma_table(png_structp png_ptr)
+{
+ png_debug(1, "in png_build_gamma_table\n");
+ if(png_ptr->gamma != 0.0)
+ {
+ if (png_ptr->bit_depth <= 8)
+ {
+ int i;
+ double g;
+
+ if (png_ptr->screen_gamma > .000001)
+ g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ else
+ g = 1.0;
+
+ png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
+ {
+
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+
+ png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ if(png_ptr->screen_gamma > 0.000001)
+ g = 1.0 / png_ptr->screen_gamma;
+ else
+ g = png_ptr->gamma; /* probably doing rgb_to_gray */
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+
+ }
+ }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+ }
+ else
+ {
+ double g;
+ int i, j, shift, num;
+ int sig_bit;
+ png_uint_32 ig;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit = (int)png_ptr->sig_bit.red;
+ if ((int)png_ptr->sig_bit.green > sig_bit)
+ sig_bit = png_ptr->sig_bit.green;
+ if ((int)png_ptr->sig_bit.blue > sig_bit)
+ sig_bit = png_ptr->sig_bit.blue;
+ }
+ else
+ {
+ sig_bit = (int)png_ptr->sig_bit.gray;
+ }
+
+ if (sig_bit > 0)
+ shift = 16 - sig_bit;
+ else
+ shift = 0;
+
+ if (png_ptr->transformations & PNG_16_TO_8)
+ {
+ if (shift < (16 - PNG_MAX_GAMMA_8))
+ shift = (16 - PNG_MAX_GAMMA_8);
+ }
+
+ if (shift > 8)
+ shift = 8;
+ if (shift < 0)
+ shift = 0;
+
+ png_ptr->gamma_shift = (png_byte)shift;
+
+ num = (1 << (8 - shift));
+
+ if (png_ptr->screen_gamma > .000001)
+ g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ else
+ g = 1.0;
+
+ png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * sizeof (png_uint_16p)));
+
+ if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
+ {
+ double fin, fout;
+ png_uint_32 last, max;
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+ }
+
+ g = 1.0 / g;
+ last = 0;
+ for (i = 0; i < 256; i++)
+ {
+ fout = ((double)i + 0.5) / 256.0;
+ fin = pow(fout, g);
+ max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
+ while (last <= max)
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)(
+ (png_uint_16)i | ((png_uint_16)i << 8));
+ last++;
+ }
+ }
+ while (last < ((png_uint_32)num << 8))
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
+ last++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_table[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
+ {
+
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * sizeof (png_uint_16p )));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_to_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+
+ if(png_ptr->screen_gamma > 0.000001)
+ g = 1.0 / png_ptr->screen_gamma;
+ else
+ g = png_ptr->gamma; /* probably doing rgb_to_gray */
+
+ png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * sizeof (png_uint_16p)));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_from_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+ }
+ }
+}
+#endif
+
--- /dev/null
+
+/* pngrutil.c - utilities to read a PNG file
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This file contains routines that are only called from within
+ * libpng itself during the course of reading an image.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
+png_uint_32
+png_get_uint_32(png_bytep buf)
+{
+ png_uint_32 i = ((png_uint_32)(*buf) << 24) +
+ ((png_uint_32)(*(buf + 1)) << 16) +
+ ((png_uint_32)(*(buf + 2)) << 8) +
+ (png_uint_32)(*(buf + 3));
+
+ return (i);
+}
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* Grab a signed 32-bit integer from a buffer in big-endian format. The
+ * data is stored in the PNG file in two's complement format, and it is
+ * assumed that the machine format for signed integers is the same. */
+png_int_32
+png_get_int_32(png_bytep buf)
+{
+ png_int_32 i = ((png_int_32)(*buf) << 24) +
+ ((png_int_32)(*(buf + 1)) << 16) +
+ ((png_int_32)(*(buf + 2)) << 8) +
+ (png_int_32)(*(buf + 3));
+
+ return (i);
+}
+#endif /* PNG_READ_pCAL_SUPPORTED */
+
+/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
+png_uint_16
+png_get_uint_16(png_bytep buf)
+{
+ png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
+ (png_uint_16)(*(buf + 1)));
+
+ return (i);
+}
+#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
+
+/* Read data, and (optionally) run it through the CRC. */
+void
+png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
+{
+ png_read_data(png_ptr, buf, length);
+ png_calculate_crc(png_ptr, buf, length);
+}
+
+/* Optionally skip data and then check the CRC. Depending on whether we
+ are reading a ancillary or critical chunk, and how the program has set
+ things up, we may calculate the CRC on the data and print a message.
+ Returns '1' if there was a CRC error, '0' otherwise. */
+int
+png_crc_finish(png_structp png_ptr, png_uint_32 skip)
+{
+ png_size_t i;
+ png_size_t istop = png_ptr->zbuf_size;
+
+ for (i = (png_size_t)skip; i > istop; i -= istop)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ }
+ if (i)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, i);
+ }
+
+ if (png_crc_error(png_ptr))
+ {
+ if ((png_ptr->chunk_name[0] & 0x20 && /* Ancillary */
+ !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
+ (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
+ png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ }
+ else
+ {
+ png_chunk_error(png_ptr, "CRC error");
+ }
+ return (1);
+ }
+
+ return (0);
+}
+
+/* Compare the CRC stored in the PNG file with that calculated by libpng from
+ the data it has read thus far. */
+int
+png_crc_error(png_structp png_ptr)
+{
+ png_byte crc_bytes[4];
+ png_uint_32 crc;
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ png_read_data(png_ptr, crc_bytes, 4);
+
+ if (need_crc)
+ {
+ crc = png_get_uint_32(crc_bytes);
+ return ((int)(crc != png_ptr->crc));
+ }
+ else
+ return (0);
+}
+
+
+/* read and check the IDHR chunk */
+void
+png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[13];
+ png_uint_32 width, height;
+ int bit_depth, color_type, compression_type, filter_type;
+ int interlace_type;
+
+ png_debug(1, "in png_handle_IHDR\n");
+
+ if (png_ptr->mode != PNG_BEFORE_IHDR)
+ png_error(png_ptr, "Out of place IHDR");
+
+ /* check the length */
+ if (length != 13)
+ png_error(png_ptr, "Invalid IHDR chunk");
+
+ png_ptr->mode |= PNG_HAVE_IHDR;
+
+ png_crc_read(png_ptr, buf, 13);
+ png_crc_finish(png_ptr, 0);
+
+ width = png_get_uint_32(buf);
+ height = png_get_uint_32(buf + 4);
+ bit_depth = buf[8];
+ color_type = buf[9];
+ compression_type = buf[10];
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
+ /* check for width and height valid values */
+ if (width == 0 || width > (png_uint_32)2147483647L || height == 0 ||
+ height > (png_uint_32)2147483647L)
+ png_error(png_ptr, "Invalid image size in IHDR");
+
+ /* check other values */
+ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
+ bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth in IHDR");
+
+ if (color_type < 0 || color_type == 1 ||
+ color_type == 5 || color_type > 6)
+ png_error(png_ptr, "Invalid color type in IHDR");
+
+ if ((color_type == PNG_COLOR_TYPE_PALETTE && bit_depth) > 8 ||
+ ((color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
+ png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
+
+ if (interlace_type >= PNG_INTERLACE_LAST)
+ png_error(png_ptr, "Unknown interlace method in IHDR");
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ png_error(png_ptr, "Unknown compression method in IHDR");
+
+ if (filter_type != PNG_FILTER_TYPE_BASE)
+ png_error(png_ptr, "Unknown filter method in IHDR");
+
+ /* set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->interlaced = (png_byte)interlace_type;
+ png_ptr->color_type = (png_byte)color_type;
+
+ /* find number of channels */
+ switch (png_ptr->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_PALETTE:
+ png_ptr->channels = 1;
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ png_ptr->channels = 4;
+ break;
+ }
+
+ /* set up other useful info */
+ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
+ png_ptr->channels);
+ png_ptr->rowbytes = ((png_ptr->width *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
+ png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
+ png_debug1(3,"channels = %d\n", png_ptr->channels);
+ png_debug1(3,"rowbytes = %d\n", png_ptr->rowbytes);
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
+ color_type, interlace_type, compression_type, filter_type);
+}
+
+/* read and check the palette */
+void
+png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_colorp palette;
+ int num, i;
+
+ png_debug(1, "in png_handle_PLTE\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before PLTE");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid PLTE after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ png_error(png_ptr, "Duplicate PLTE chunk");
+
+ png_ptr->mode |= PNG_HAVE_PLTE;
+
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ if (length % 3)
+ {
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_warning(png_ptr, "Invalid palette chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else
+ {
+ png_error(png_ptr, "Invalid palette chunk");
+ }
+ }
+
+ num = (int)length / 3;
+ palette = (png_colorp)png_zalloc(png_ptr, (uInt)num, sizeof (png_color));
+ png_ptr->flags |= PNG_FLAG_FREE_PALETTE;
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[3];
+
+ png_crc_read(png_ptr, buf, 3);
+ /* don't depend upon png_color being any order */
+ palette[i].red = buf[0];
+ palette[i].green = buf[1];
+ palette[i].blue = buf[2];
+ }
+
+ /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
+ whatever the normal CRC configuration tells us. However, if we
+ have an RGB image, the PLTE can be considered ancillary, so
+ we will act as though it is. */
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+#endif
+ {
+ png_crc_finish(png_ptr, 0);
+ }
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
+ {
+ /* If we don't want to use the data from an ancillary chunk,
+ we have two options: an error abort, or a warning and we
+ ignore the data in this chunk (which should be OK, since
+ it's considered ancillary for a RGB or RGBA image). */
+ if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
+ {
+ png_chunk_error(png_ptr, "CRC error");
+ }
+ else
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ png_ptr->flags &= ~PNG_FLAG_FREE_PALETTE;
+ png_zfree(png_ptr, palette);
+ return;
+ }
+ }
+ /* Otherwise, we (optionally) emit a warning and use the chunk. */
+ else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ }
+ }
+#endif
+ png_ptr->palette = palette;
+ png_ptr->num_palette = (png_uint_16)num;
+ png_set_PLTE(png_ptr, info_ptr, palette, num);
+
+#if defined (PNG_READ_tRNS_SUPPORTED)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
+ {
+ if (png_ptr->num_trans > png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
+ png_ptr->num_trans = png_ptr->num_palette;
+ }
+ }
+ }
+#endif
+
+}
+
+void
+png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_IEND\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
+ {
+ png_error(png_ptr, "No image in file");
+
+ /* to quiet compiler warnings about unused info_ptr */
+ if (info_ptr == NULL)
+ return;
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT | PNG_HAVE_IEND;
+
+ if (length != 0)
+ {
+ png_warning(png_ptr, "Incorrect IEND chunk length");
+ }
+ png_crc_finish(png_ptr, length);
+}
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+void
+png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_uint_32 igamma;
+ float file_gamma;
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_gAMA\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before gAMA");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid gAMA after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place gAMA chunk");
+
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ && !(info_ptr->valid & PNG_INFO_sRGB)
+#endif
+ )
+ {
+ png_warning(png_ptr, "Duplicate gAMA chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 4)
+ {
+ png_warning(png_ptr, "Incorrect gAMA chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ igamma = png_get_uint_32(buf);
+ /* check for zero gamma */
+ if (igamma == 0)
+ return;
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ if(igamma != (png_uint_32)45000L)
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect gAMA value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr, "igamma = %lu\n", igamma);
+#endif
+ return;
+ }
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+ file_gamma = (float)igamma / (float)100000.0;
+#ifdef PNG_READ_GAMMA_SUPPORTED
+ png_ptr->gamma = file_gamma;
+#endif
+ png_set_gAMA(png_ptr, info_ptr, file_gamma);
+}
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+void
+png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_sBIT\n");
+
+ buf[0] = buf[1] = buf[2] = buf[3] = 0;
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sBIT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sBIT after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ {
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place sBIT chunk");
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT)
+ {
+ png_warning(png_ptr, "Duplicate sBIT chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 3;
+ else
+ truelen = (png_size_t)png_ptr->channels;
+
+ if (length != truelen)
+ {
+ png_warning(png_ptr, "Incorrect sBIT chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_ptr->sig_bit.red = buf[0];
+ png_ptr->sig_bit.green = buf[1];
+ png_ptr->sig_bit.blue = buf[2];
+ png_ptr->sig_bit.alpha = buf[3];
+ }
+ else
+ {
+ png_ptr->sig_bit.gray = buf[0];
+ png_ptr->sig_bit.red = buf[0];
+ png_ptr->sig_bit.green = buf[0];
+ png_ptr->sig_bit.blue = buf[0];
+ png_ptr->sig_bit.alpha = buf[1];
+ }
+ png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+void
+png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[4];
+ png_uint_32 val;
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+
+ png_debug(1, "in png_handle_cHRM\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sBIT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid cHRM after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Missing PLTE before cHRM");
+
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_cHRM
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ && !(info_ptr->valid & PNG_INFO_sRGB)
+#endif
+ )
+ {
+ png_warning(png_ptr, "Duplicate cHRM chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 32)
+ {
+ png_warning(png_ptr, "Incorrect cHRM chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ white_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ white_y = (float)val / (float)100000.0;
+
+ if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
+ white_x + white_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point");
+ png_crc_finish(png_ptr, 24);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ red_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ red_y = (float)val / (float)100000.0;
+
+ if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
+ red_x + red_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point");
+ png_crc_finish(png_ptr, 16);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ green_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ green_y = (float)val / (float)100000.0;
+
+ if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
+ green_x + green_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point");
+ png_crc_finish(png_ptr, 8);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ blue_x = (float)val / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ val = png_get_uint_32(buf);
+ blue_y = (float)val / (float)100000.0;
+
+ if (blue_x < (float)0 || blue_x > (float)0.8 || blue_y < (float)0 ||
+ blue_y > (float)0.8 || blue_x + blue_y > (float)1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point");
+ png_crc_finish(png_ptr, 0);
+ return;
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ {
+ if (fabs(white_x - (float).3127) > (float).001 ||
+ fabs(white_y - (float).3290) > (float).001 ||
+ fabs( red_x - (float).6400) > (float).001 ||
+ fabs( red_y - (float).3300) > (float).001 ||
+ fabs(green_x - (float).3000) > (float).001 ||
+ fabs(green_y - (float).6000) > (float).001 ||
+ fabs( blue_x - (float).1500) > (float).001 ||
+ fabs( blue_y - (float).0600) > (float).001)
+ {
+
+ png_warning(png_ptr,
+ "Ignoring incorrect cHRM value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
+ white_x, white_y, red_x, red_y);
+ fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
+ green_x, green_y, blue_x, blue_y);
+#endif
+ }
+ return;
+ }
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+ png_set_cHRM(png_ptr, info_ptr,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+}
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+void
+png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ int intent;
+ png_byte buf[1];
+
+ png_debug(1, "in png_handle_sRGB\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sRGB");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sRGB after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place sRGB chunk");
+
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sRGB)
+ {
+ png_warning(png_ptr, "Duplicate sRGB chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 1)
+ {
+ png_warning(png_ptr, "Incorrect sRGB chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 1);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ intent = buf[0];
+ /* check for bad intent */
+ if (intent >= PNG_sRGB_INTENT_LAST)
+ {
+ png_warning(png_ptr, "Unknown sRGB intent");
+ return;
+ }
+
+#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
+ if ((info_ptr->valid & PNG_INFO_gAMA))
+ if((png_uint_32)(png_ptr->gamma*(float)100000.+.5) != (png_uint_32)45000L)
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect gAMA value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr,"gamma=%f\n",png_ptr->gamma);
+#endif
+ }
+#endif /* PNG_READ_gAMA_SUPPORTED */
+
+#ifdef PNG_READ_cHRM_SUPPORTED
+ if (info_ptr->valid & PNG_INFO_cHRM)
+ if (fabs(info_ptr->x_white - (float).3127) > (float).001 ||
+ fabs(info_ptr->y_white - (float).3290) > (float).001 ||
+ fabs( info_ptr->x_red - (float).6400) > (float).001 ||
+ fabs( info_ptr->y_red - (float).3300) > (float).001 ||
+ fabs(info_ptr->x_green - (float).3000) > (float).001 ||
+ fabs(info_ptr->y_green - (float).6000) > (float).001 ||
+ fabs( info_ptr->x_blue - (float).1500) > (float).001 ||
+ fabs( info_ptr->y_blue - (float).0600) > (float).001)
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect cHRM value when sRGB is also present");
+ }
+#endif /* PNG_READ_cHRM_SUPPORTED */
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
+}
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+void
+png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_tRNS\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tRNS");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid tRNS after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
+ {
+ png_warning(png_ptr, "Duplicate tRNS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Missing PLTE before tRNS");
+ }
+ else if (length > png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ if (length == 0)
+ {
+ png_warning(png_ptr, "Zero length tRNS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_ptr->trans = (png_bytep)png_malloc(png_ptr, length);
+ png_ptr->flags |= PNG_FLAG_FREE_TRANS;
+ png_crc_read(png_ptr, png_ptr->trans, (png_size_t)length);
+ png_ptr->num_trans = (png_uint_16)length;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_byte buf[6];
+
+ if (length != 6)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, (png_size_t)length);
+ png_ptr->num_trans = 1;
+ png_ptr->trans_values.red = png_get_uint_16(buf);
+ png_ptr->trans_values.green = png_get_uint_16(buf + 2);
+ png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_byte buf[6];
+
+ if (length != 2)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 2);
+ png_ptr->num_trans = 1;
+ png_ptr->trans_values.gray = png_get_uint_16(buf);
+ }
+ else
+ {
+ png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_tRNS(png_ptr, info_ptr, png_ptr->trans, png_ptr->num_trans,
+ &(png_ptr->trans_values));
+}
+#endif
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+void
+png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[6];
+
+ png_debug(1, "in png_handle_bKGD\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before bKGD");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid bKGD after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before bKGD");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_bKGD)
+ {
+ png_warning(png_ptr, "Duplicate bKGD chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 1;
+ else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ truelen = 6;
+ else
+ truelen = 2;
+
+ if (length != truelen)
+ {
+ png_warning(png_ptr, "Incorrect bKGD chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ /* We convert the index value into RGB components so that we can allow
+ * arbitrary RGB values for background when we have transparency, and
+ * so it is easy to determine the RGB values of the background color
+ * from the info_ptr struct. */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.index = buf[0];
+ png_ptr->background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
+ png_ptr->background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
+ png_ptr->background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
+ }
+ else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
+ {
+ png_ptr->background.red =
+ png_ptr->background.green =
+ png_ptr->background.blue =
+ png_ptr->background.gray = png_get_uint_16(buf);
+ }
+ else
+ {
+ png_ptr->background.red = png_get_uint_16(buf);
+ png_ptr->background.green = png_get_uint_16(buf + 2);
+ png_ptr->background.blue = png_get_uint_16(buf + 4);
+ }
+
+ png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+void
+png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ int num, i;
+
+ png_debug(1, "in png_handle_hIST\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before hIST");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid hIST after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before hIST");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_hIST)
+ {
+ png_warning(png_ptr, "Duplicate hIST chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != (png_uint_32)(2 * png_ptr->num_palette))
+ {
+ png_warning(png_ptr, "Incorrect hIST chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ num = (int)length / 2;
+ png_ptr->hist = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(num * sizeof (png_uint_16)));
+ png_ptr->flags |= PNG_FLAG_FREE_HIST;
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[2];
+
+ png_crc_read(png_ptr, buf, 2);
+ png_ptr->hist[i] = png_get_uint_16(buf);
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_hIST(png_ptr, info_ptr, png_ptr->hist);
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+void
+png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_pHYs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pHYS");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pHYS after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_warning(png_ptr, "Duplicate pHYS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect pHYs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ res_x = png_get_uint_32(buf);
+ res_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+void
+png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 offset_x, offset_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_oFFs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before oFFs");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid oFFs after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_warning(png_ptr, "Duplicate oFFs chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect oFFs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ offset_x = png_get_uint_32(buf);
+ offset_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* read the pCAL chunk (png-scivis-19970203) */
+void
+png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_charp purpose;
+ png_int_32 X0, X1;
+ png_byte type, nparams;
+ png_charp buf, units, endptr;
+ png_charpp params;
+ png_size_t slength;
+ int i;
+
+ png_debug(1, "in png_handle_pCAL\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pCAL");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pCAL after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL)
+ {
+ png_warning(png_ptr, "Duplicate pCAL chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_debug1(2, "Allocating and reading pCAL chunk data (%d bytes)\n",
+ length + 1);
+ purpose = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)purpose, slength);
+
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ purpose[slength] = 0x00; /* null terminate the last string */
+
+ png_debug(3, "Finding end of pCAL purpose string\n");
+ for (buf = purpose; *buf; buf++)
+ /* empty loop */ ;
+
+ endptr = purpose + slength;
+
+ /* We need to have at least 12 bytes after the purpose string
+ in order to get the parameter information. */
+ if (endptr <= buf + 12)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
+ X0 = png_get_int_32((png_bytep)buf+1);
+ X1 = png_get_int_32((png_bytep)buf+5);
+ type = buf[9];
+ nparams = buf[10];
+ units = buf + 11;
+
+ png_debug(3, "Checking pCAL equation type and number of parameters\n");
+ /* Check that we have the right number of parameters for known
+ equation types. */
+ if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
+ (type == PNG_EQUATION_BASE_E && nparams != 3) ||
+ (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
+ (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
+ {
+ png_warning(png_ptr, "Invalid pCAL parameters for equation type");
+ png_free(png_ptr, purpose);
+ return;
+ }
+ else if (type >= PNG_EQUATION_LAST)
+ {
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+ }
+
+ for (buf = units; *buf; buf++)
+ /* Empty loop to move past the units string. */ ;
+
+ png_debug(3, "Allocating pCAL parameters array\n");
+ params = (png_charpp)png_malloc(png_ptr, (png_uint_32)(nparams
+ *sizeof(png_charp))) ;
+
+ /* Get pointers to the start of each parameter string. */
+ for (i = 0; i < (int)nparams; i++)
+ {
+ buf++; /* Skip the null string terminator from previous parameter. */
+
+ png_debug1(3, "Reading pCAL parameter %d\n", i);
+ for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++)
+ /* Empty loop to move past each parameter string */ ;
+
+ /* Make sure we haven't run out of data yet */
+ if (buf > endptr)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+ return;
+ }
+ }
+
+ png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
+ units, params);
+
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+void
+png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[7];
+ png_time mod_time;
+
+ png_debug(1, "in png_handle_tIME\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Out of place tIME chunk");
+ else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME)
+ {
+ png_warning(png_ptr, "Duplicate tIME chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ if (length != 7)
+ {
+ png_warning(png_ptr, "Incorrect tIME chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 7);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ mod_time.second = buf[6];
+ mod_time.minute = buf[5];
+ mod_time.hour = buf[4];
+ mod_time.day = buf[3];
+ mod_time.month = buf[2];
+ mod_time.year = png_get_uint_16(buf);
+
+ png_set_tIME(png_ptr, info_ptr, &mod_time);
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+void
+png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp key;
+ png_charp text;
+ png_uint_32 skip = 0;
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_tEXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tEXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ key = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)key, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ key[slength] = 0x00;
+
+ for (text = key; *text; text++)
+ /* empty loop to find end of key */ ;
+
+ if (text != key + slength)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+/* note: this does not correctly handle chunks that are > 64K under DOS */
+void
+png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ static char msg[] = "Error decoding zTXt chunk";
+ png_textp text_ptr;
+ png_charp key;
+ png_charp text;
+ int comp_type = PNG_TEXT_COMPRESSION_NONE;
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_zTXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before zTXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We will no doubt have problems with chunks even half this size, but
+ there is no hard and fast rule to tell us where to stop. */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr,"zTXt chunk too large to fit in memory");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ key = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)key, slength);
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ key[slength] = 0x00;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt must have some text after the keyword */
+ if (text == key + slength)
+ {
+ png_warning(png_ptr, "Zero length zTXt chunk");
+ }
+ else if ((comp_type = *(++text)) == PNG_TEXT_COMPRESSION_zTXt)
+ {
+ png_size_t text_size, key_size;
+ text++;
+
+ png_ptr->zstream.next_in = (png_bytep)text;
+ png_ptr->zstream.avail_in = (uInt)(length - (text - key));
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ key_size = (png_size_t)(text - key);
+ text_size = 0;
+ text = NULL;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ int ret;
+
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_warning(png_ptr, png_ptr->zstream.msg);
+ else
+ png_warning(png_ptr, msg);
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (text == NULL)
+ {
+ text_size = key_size + sizeof(msg) + 1;
+ text = (png_charp)png_malloc(png_ptr, (png_uint_32)text_size);
+ png_memcpy(text, key, key_size);
+ }
+
+ text[text_size - 1] = 0x00;
+
+ /* Copy what we can of the error message into the text chunk */
+ text_size = (png_size_t)(slength - (text - key) - 1);
+ text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
+ png_memcpy(text + key_size, msg, text_size + 1);
+ break;
+ }
+ if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
+ + key_size + 1));
+ png_memcpy(text + key_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_memcpy(text, key, key_size);
+ text_size = key_size + png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out;
+ *(text + text_size) = 0x00;
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = (png_charp)png_malloc(png_ptr, (png_uint_32)(text_size +
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = 0x00;
+ }
+ if (ret != Z_STREAM_END)
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ png_free(png_ptr, key);
+ key = text;
+ text += key_size;
+ }
+ else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */
+ {
+ png_size_t text_size;
+#if !defined(PNG_NO_STDIO)
+ char umsg[50];
+
+ sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
+ png_warning(png_ptr, umsg);
+#else
+ png_warning(png_ptr, "Unknown zTXt compression type");
+#endif
+
+ /* Copy what we can of the error message into the text chunk */
+ text_size = (png_size_t)(slength - (text - key) - 1);
+ text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
+ png_memcpy(text, msg, text_size + 1);
+ }
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = comp_type;
+ text_ptr->key = key;
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+}
+#endif
+
+/* This function is called when we haven't found a handler for a
+ chunk. If there isn't a problem with the chunk itself (ie bad
+ chunk name, CRC, or a critical chunk), the chunk is silently ignored. */
+void
+png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_unknown\n");
+
+ /* In the future we can have code here that calls user-supplied
+ * callback functions for unknown chunks before they are ignored or
+ * cause an error.
+ */
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+ png_chunk_error(png_ptr, "unknown critical chunk");
+
+ /* to quiet compiler warnings about unused info_ptr */
+ if (info_ptr == NULL)
+ return;
+ }
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ png_crc_finish(png_ptr, length);
+
+}
+
+/* This function is called to verify that a chunk name is valid.
+ This function can't have the "critical chunk check" incorporated
+ into it, since in the future we will need to be able to call user
+ functions to handle unknown critical chunks after we check that
+ the chunk name itself is valid. */
+
+#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
+
+void
+png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
+{
+ png_debug(1, "in png_check_chunk_name\n");
+ if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
+ isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
+ {
+ png_chunk_error(png_ptr, "invalid chunk type");
+ }
+}
+
+/* Combines the row recently read in with the existing pixels in the
+ row. This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined,
+ a zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel. If
+ you want all pixels to be combined, pass 0xff (255) in mask. */
+void
+png_combine_row(png_structp png_ptr, png_bytep row,
+ int mask)
+{
+ png_debug(1,"in png_combine_row\n");
+ if (mask == 0xff)
+ {
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)((png_ptr->width *
+ png_ptr->row_info.pixel_depth + 7) >> 3));
+ }
+ else
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_inc, s_start, s_end;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_start, s_end, s_inc;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ int value;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_start, s_end, s_inc;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ int value;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ default:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ png_byte m = 0x80;
+
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ png_memcpy(dp, sp, pixel_bytes);
+ }
+
+ sp += pixel_bytes;
+ dp += pixel_bytes;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ }
+ }
+}
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+void
+png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
+ png_uint_32 transformations)
+{
+ png_debug(1,"in png_do_read_interlace\n");
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ int jstop = png_pass_inc[pass];
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 7);
+ dshift = (int)((final_width + 7) & 7);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x1);
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
+ png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ int jstop = png_pass_inc[pass];
+ png_uint_32 i;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)(((row_info->width + 3) & 3) << 1);
+ dshift = (int)(((final_width + 3) & 3) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
+ dshift = (int)((3 - ((final_width + 3) & 3)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x3);
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+ int jstop = png_pass_inc[pass];
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)(((row_info->width + 1) & 1) << 2);
+ dshift = (int)(((final_width + 1) & 1) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (int)((1 - ((row_info->width + 1) & 1)) << 2);
+ dshift = (int)((1 - ((final_width + 1) & 1)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v = (png_byte)((*sp >> sshift) & 0xf);
+ int j;
+
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ default:
+ {
+ png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
+ png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
+ png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
+ int jstop = png_pass_inc[pass];
+ png_uint_32 i;
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sp, pixel_bytes);
+ for (j = 0; j < jstop; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sp -= pixel_bytes;
+ }
+ break;
+ }
+ }
+ row_info->width = final_width;
+ row_info->rowbytes = ((final_width *
+ (png_uint_32)row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+void
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
+ png_bytep prev_row, int filter)
+{
+ png_debug(1, "in png_read_filter_row\n");
+ png_debug2(2,"row = %d, filter = %d\n", png_ptr->row_number, filter);
+
+
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+ case PNG_FILTER_VALUE_SUB:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) / 8;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_UP:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_AVG:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) / 8;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) / 2)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ (int)(*pp++ + *lp++) / 2) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_PAETH:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) / 8;
+ png_uint_32 istop=row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) /* use leftover rp,pp */
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ default:
+ png_warning(png_ptr, "Ignoring bad adaptive filter type");
+ *row=0;
+ break;
+ }
+}
+
+void
+png_read_finish_row(png_structp png_ptr)
+{
+ png_debug(1, "in png_read_finish_row\n");
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
+
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (!(png_ptr->num_rows))
+ continue;
+ }
+ else /* if (png_ptr->transformations & PNG_INTERLACE) */
+ break;
+ } while (png_ptr->iwidth == 0);
+
+ if (png_ptr->pass < 7)
+ return;
+ }
+
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ {
+ char extra;
+ int ret;
+
+ png_ptr->zstream.next_out = (Byte *)&extra;
+ png_ptr->zstream.avail_out = (uInt)1;
+ for(;;)
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_error(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression Error");
+
+ if (!(png_ptr->zstream.avail_out))
+ png_error(png_ptr, "Extra compressed data");
+
+ }
+ png_ptr->zstream.avail_out = 0;
+ }
+
+ if (png_ptr->idat_size || png_ptr->zstream.avail_in)
+ png_error(png_ptr, "Extra compression data");
+
+ inflateReset(&png_ptr->zstream);
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+}
+
+void
+png_read_start_row(png_structp png_ptr)
+{
+ int max_pixel_depth;
+ png_uint_32 row_bytes;
+
+ png_debug(1, "in png_read_start_row\n");
+ png_ptr->zstream.avail_in = 0;
+ png_init_read_transformations(png_ptr);
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ else
+ png_ptr->num_rows = png_ptr->height;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
+ row_bytes = ((png_ptr->iwidth *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
+ png_ptr->irowbytes = (png_size_t)row_bytes;
+ if((png_uint_32)png_ptr->irowbytes != row_bytes)
+ png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->iwidth = png_ptr->width;
+ png_ptr->irowbytes = png_ptr->rowbytes + 1;
+ }
+ max_pixel_depth = png_ptr->pixel_depth;
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
+ max_pixel_depth = 8;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 24;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (max_pixel_depth < 8)
+ max_pixel_depth = 8;
+ if (png_ptr->num_trans)
+ max_pixel_depth *= 2;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (png_ptr->num_trans)
+ {
+ max_pixel_depth *= 4;
+ max_pixel_depth /= 3;
+ }
+ }
+ }
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & (PNG_FILLER))
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ max_pixel_depth = 32;
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (max_pixel_depth <= 8)
+ max_pixel_depth = 16;
+ else
+ max_pixel_depth = 32;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (max_pixel_depth <= 32)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 64;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ {
+ if (
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
+#endif
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ (png_ptr->transformations & (PNG_FILLER)) ||
+#endif
+ png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (max_pixel_depth <= 16)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 64;
+ }
+ else
+ {
+ if (max_pixel_depth <= 8)
+ max_pixel_depth = 24;
+ else
+ max_pixel_depth = 48;
+ }
+ }
+#endif
+
+ /* align the width on the next larger 8 pixels. Mainly used
+ for interlacing */
+ row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
+ /* calculate the maximum bytes needed, adding a byte and a pixel
+ for safety's sake */
+ row_bytes = ((row_bytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
+ 1 + ((max_pixel_depth + 7) >> 3);
+#ifdef PNG_MAX_MALLOC_64K
+ if (row_bytes > (png_uint_32)65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, row_bytes);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
+ png_ptr->rowbytes + 1));
+
+ png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+
+ png_debug1(3, "width = %d,\n", png_ptr->width);
+ png_debug1(3, "height = %d,\n", png_ptr->height);
+ png_debug1(3, "iwidth = %d,\n", png_ptr->iwidth);
+ png_debug1(3, "num_rows = %d\n", png_ptr->num_rows);
+ png_debug1(3, "rowbytes = %d,\n", png_ptr->rowbytes);
+ png_debug1(3, "irowbytes = %d,\n", png_ptr->irowbytes);
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+}
--- /dev/null
+
+/* pngset.c - storage of image information into info struct
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * The functions here are used during reads to store data from the file
+ * into the info struct, and during writes to store application data
+ * into the info struct for writing into the file. This abstracts the
+ * info struct and allows us to change the structure in the future.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED)
+void
+png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background)
+{
+ png_debug1(1, "in %s storage function\n", "bKGD");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->background), background, sizeof(png_color_16));
+ info_ptr->valid |= PNG_INFO_bKGD;
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+void
+png_set_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double white_x, double white_y, double red_x, double red_y,
+ double green_x, double green_y, double blue_x, double blue_y)
+{
+ png_debug1(1, "in %s storage function\n", "cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_white = (float)white_x;
+ info_ptr->y_white = (float)white_y;
+ info_ptr->x_red = (float)red_x;
+ info_ptr->y_red = (float)red_y;
+ info_ptr->x_green = (float)green_x;
+ info_ptr->y_green = (float)green_y;
+ info_ptr->x_blue = (float)blue_x;
+ info_ptr->y_blue = (float)blue_y;
+ info_ptr->valid |= PNG_INFO_cHRM;
+}
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+void
+png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma)
+{
+ png_debug1(1, "in %s storage function\n", "gAMA");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->gamma = (float)file_gamma;
+ info_ptr->valid |= PNG_INFO_gAMA;
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED)
+void
+png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist)
+{
+ png_debug1(1, "in %s storage function\n", "hIST");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->hist = hist;
+ info_ptr->valid |= PNG_INFO_hIST;
+}
+#endif
+
+void
+png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type,
+ int filter_type)
+{
+ int rowbytes_per_pixel;
+ png_debug1(1, "in %s storage function\n", "IHDR");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->width = width;
+ info_ptr->height = height;
+ info_ptr->bit_depth = (png_byte)bit_depth;
+ info_ptr->color_type =(png_byte) color_type;
+ info_ptr->compression_type = (png_byte)compression_type;
+ info_ptr->filter_type = (png_byte)filter_type;
+ info_ptr->interlace_type = (png_byte)interlace_type;
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+
+ /* check for overflow */
+ rowbytes_per_pixel = (info_ptr->pixel_depth + 7) >> 3;
+ if (( width > (png_uint_32)2147483647L/rowbytes_per_pixel))
+ {
+ png_warning(png_ptr,
+ "Width too large to process image data; rowbytes will overflow.");
+ info_ptr->rowbytes = (png_size_t)0;
+ }
+ else
+ info_ptr->rowbytes = (info_ptr->width * info_ptr->pixel_depth + 7) >> 3;
+}
+
+#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+void
+png_set_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 offset_x, png_uint_32 offset_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "oFFs");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_offset = offset_x;
+ info_ptr->y_offset = offset_y;
+ info_ptr->offset_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_oFFs;
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED)
+void
+png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params)
+{
+ png_uint_32 length;
+ int i;
+
+ png_debug1(1, "in %s storage function\n", "pCAL");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ length = png_strlen(purpose) + 1;
+ png_debug1(3, "allocating purpose for info (%d bytes)\n", length);
+ info_ptr->pcal_purpose = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length);
+
+ png_debug(3, "storing X0, X1, type, and nparams in info\n");
+ info_ptr->pcal_X0 = X0;
+ info_ptr->pcal_X1 = X1;
+ info_ptr->pcal_type = (png_byte)type;
+ info_ptr->pcal_nparams = (png_byte)nparams;
+
+ length = png_strlen(units) + 1;
+ png_debug1(3, "allocating units for info (%d bytes)\n", length);
+ info_ptr->pcal_units = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_units, units, (png_size_t)length);
+
+ info_ptr->pcal_params = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)((nparams + 1) * sizeof(png_charp)));
+ info_ptr->pcal_params[nparams] = NULL;
+
+ for (i = 0; i < nparams; i++)
+ {
+ length = png_strlen(params[i]) + 1;
+ png_debug2(3, "allocating parameter %d for info (%d bytes)\n", i, length);
+ info_ptr->pcal_params[i] = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length);
+ }
+
+ info_ptr->valid |= PNG_INFO_pCAL;
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED)
+void
+png_set_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 res_x, png_uint_32 res_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "pHYs");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_pixels_per_unit = res_x;
+ info_ptr->y_pixels_per_unit = res_y;
+ info_ptr->phys_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_pHYs;
+}
+#endif
+
+void
+png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
+ png_colorp palette, int num_palette)
+{
+ png_debug1(1, "in %s storage function\n", "PLTE");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->palette = palette;
+ info_ptr->num_palette = (png_uint_16)num_palette;
+ info_ptr->valid |= PNG_INFO_PLTE;
+}
+
+#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED)
+void
+png_set_sBIT(png_structp png_ptr, png_infop info_ptr,
+ png_color_8p sig_bit)
+{
+ png_debug1(1, "in %s storage function\n", "sBIT");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->sig_bit), sig_bit, sizeof (png_color_8));
+ info_ptr->valid |= PNG_INFO_sBIT;
+}
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
+void
+png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent)
+{
+ png_debug1(1, "in %s storage function\n", "sRGB");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->srgb_intent = (png_byte)intent;
+ info_ptr->valid |= PNG_INFO_sRGB;
+}
+void
+png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
+ int intent)
+{
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+ float file_gamma;
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+#endif
+ png_debug1(1, "in %s storage function\n", "sRGB_gAMA_and_cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_set_sRGB(png_ptr, info_ptr, intent);
+
+#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED)
+ file_gamma = (float).45;
+ png_set_gAMA(png_ptr, info_ptr, file_gamma);
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED)
+ white_x = (float).3127;
+ white_y = (float).3290;
+ red_x = (float).64;
+ red_y = (float).33;
+ green_x = (float).30;
+ green_y = (float).60;
+ blue_x = (float).15;
+ blue_y = (float).06;
+
+ png_set_cHRM(png_ptr, info_ptr,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+
+#endif
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+void
+png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
+ int num_text)
+{
+ int i;
+
+ png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ?
+ "text" : (png_const_charp)png_ptr->chunk_name));
+
+ if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
+ return;
+
+ /* Make sure we have enough space in the "text" array in info_struct
+ * to hold all of the incoming text_ptr objects.
+ */
+ if (info_ptr->num_text + num_text > info_ptr->max_text)
+ {
+ if (info_ptr->text != NULL)
+ {
+ png_textp old_text;
+ int old_max;
+
+ old_max = info_ptr->max_text;
+ info_ptr->max_text = info_ptr->num_text + num_text + 8;
+ old_text = info_ptr->text;
+ info_ptr->text = (png_textp)png_malloc(png_ptr,
+ (png_uint_32)(info_ptr->max_text * sizeof (png_text)));
+ png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max *
+ sizeof(png_text)));
+ png_free(png_ptr, old_text);
+ }
+ else
+ {
+ info_ptr->max_text = num_text + 8;
+ info_ptr->num_text = 0;
+ info_ptr->text = (png_textp)png_malloc(png_ptr,
+ (png_uint_32)(info_ptr->max_text * sizeof (png_text)));
+ }
+ png_debug1(3, "allocated %d entries for info_ptr->text\n",
+ info_ptr->max_text);
+ }
+
+ for (i = 0; i < num_text; i++)
+ {
+ png_textp textp = &(info_ptr->text[info_ptr->num_text]);
+
+ if (text_ptr[i].text == NULL)
+ text_ptr[i].text = (png_charp)"";
+
+ if (text_ptr[i].text[0] == '\0')
+ {
+ textp->text_length = 0;
+ textp->compression = PNG_TEXT_COMPRESSION_NONE;
+ }
+ else
+ {
+ textp->text_length = png_strlen(text_ptr[i].text);
+ textp->compression = text_ptr[i].compression;
+ }
+ textp->text = text_ptr[i].text;
+ textp->key = text_ptr[i].key;
+ info_ptr->num_text++;
+ png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text);
+ }
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED)
+void
+png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time)
+{
+ png_debug1(1, "in %s storage function\n", "tIME");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->mod_time), mod_time, sizeof (png_time));
+ info_ptr->valid |= PNG_INFO_tIME;
+}
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED)
+void
+png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep trans, int num_trans, png_color_16p trans_values)
+{
+ png_debug1(1, "in %s storage function\n", "tRNS");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (trans != NULL)
+ {
+ info_ptr->trans = trans;
+ }
+
+ if (trans_values != NULL)
+ {
+ png_memcpy(&(info_ptr->trans_values), trans_values,
+ sizeof(png_color_16));
+ if (num_trans == 0)
+ num_trans = 1;
+ }
+ info_ptr->num_trans = (png_uint_16)num_trans;
+ info_ptr->valid |= PNG_INFO_tRNS;
+}
+#endif
+
--- /dev/null
+
+/* pngtest.c - a simple test program to test libpng
+ *
+ * libpng 1.0.3 -January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This program reads in a PNG image, writes it out again, and then
+ * compares the two files. If the files are identical, this shows that
+ * the basic chunk handling, filtering, and (de)compression code is working
+ * properly. It does not currently test all of the transforms, although
+ * it probably should.
+ *
+ * The program will report "FAIL" in certain legitimate cases:
+ * 1) when the compression level or filter selection method is changed.
+ * 2) when the chunk size is not 8K.
+ * 3) unknown ancillary chunks exist in the input file.
+ * 4) others not listed here...
+ * In these cases, it is best to check with another tool such as "pngcheck"
+ * to see what the differences between the two images are.
+ *
+ * If a filename is given on the command-line, then this file is used
+ * for the input, rather than the default "pngtest.png". This allows
+ * testing a wide variety of files easily. You can also test a number
+ * of files at once by typing "pngtest -m file1.png file2.png ..."
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
+#ifndef PNG_DEBUG
+#define PNG_DEBUG 0
+#endif
+
+#include "png.h"
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+static int tIME_chunk_present=0;
+static char tIME_string[30] = "no tIME chunk present in file";
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+
+int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
+
+#ifdef __TURBOC__
+#include <mem.h>
+#endif
+
+/* defined so I can write to a file on gui/windowing platforms */
+/* #define STDERR stderr */
+#define STDERR stdout /* for DOS */
+
+/* example of using row callbacks to make a simple progress meter */
+static int status_pass=1;
+static int status_dots_requested=0;
+static int status_dots=1;
+
+void
+read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
+{
+ if(png_ptr == NULL || row_number > 0x3fffffffL) return;
+ if(status_pass != pass)
+ {
+ fprintf(stdout,"\n Pass %d: ",pass);
+ status_pass = pass;
+ status_dots = 30;
+ }
+ status_dots--;
+ if(status_dots == 0)
+ {
+ fprintf(stdout, "\n ");
+ status_dots=30;
+ }
+ fprintf(stdout, "r");
+}
+
+void
+write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
+{
+ if(png_ptr == NULL || row_number > 0x3fffffffL || pass > 7) return;
+ fprintf(stdout, "w");
+}
+
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+/* example of using user transform callback (we don't transform anything,
+ but merely count the zero samples) */
+
+static png_uint_32 zero_samples;
+
+void
+count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
+{
+ png_bytep dp = data;
+ if(png_ptr == NULL)return;
+
+ /* contents of row_info:
+ * png_uint_32 width width of row
+ * png_uint_32 rowbytes number of bytes in row
+ * png_byte color_type color type of pixels
+ * png_byte bit_depth bit depth of samples
+ * png_byte channels number of channels (1-4)
+ * png_byte pixel_depth bits per pixel (depth*channels)
+ */
+
+ /* counts the number of zero samples (or zero pixels if color_type is 3 */
+
+ if(row_info->color_type == 0 || row_info->color_type == 3)
+ {
+ int pos=0;
+ png_uint_32 n, nstop;
+ for (n=0, nstop=row_info->width; n<nstop; n++)
+ {
+ if(row_info->bit_depth == 1)
+ {
+ if(((*dp << pos++ )& 0x80) == 0) zero_samples++;
+ if(pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+ if(row_info->bit_depth == 2)
+ {
+ if(((*dp << (pos+=2))& 0xc0) == 0) zero_samples++;
+ if(pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+ if(row_info->bit_depth == 4)
+ {
+ if(((*dp << (pos+=4))& 0xf0) == 0) zero_samples++;
+ if(pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+ if(row_info->bit_depth == 8)
+ if(*dp++ == 0) zero_samples++;
+ if(row_info->bit_depth == 16)
+ {
+ if((*dp | *(dp+1)) == 0) zero_samples++;
+ dp+=2;
+ }
+ }
+ }
+ else /* other color types */
+ {
+ png_uint_32 n, nstop;
+ int channel;
+ int color_channels = row_info->channels;
+ if(row_info->color_type > 3)color_channels--;
+
+ for (n=0, nstop=row_info->width; n<nstop; n++)
+ {
+ for (channel = 0; channel < color_channels; channel++)
+ {
+ if(row_info->bit_depth == 8)
+ if(*dp++ == 0) zero_samples++;
+ if(row_info->bit_depth == 16)
+ {
+ if((*dp | *(dp+1)) == 0) zero_samples++;
+ dp+=2;
+ }
+ }
+ if(row_info->color_type > 3)
+ {
+ dp++;
+ if(row_info->bit_depth == 16)dp++;
+ }
+ }
+ }
+}
+#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
+
+static int verbose = 0;
+static int wrote_question = 0;
+
+#if defined(PNG_NO_STDIO)
+/* START of code to validate stdio-free compilation */
+/* These copies of the default read/write functions come from pngrio.c and */
+/* pngwio.c. They allow "don't include stdio" testing of the library. */
+/* This is the function that does the actual reading of data. If you are
+ not reading from a standard C stream, you should create a replacement
+ read_data function and use it at run time with png_set_read_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+static void
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_size_t check;
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+ check = (png_size_t)fread(data, (png_size_t)1, length,
+ (FILE *)png_ptr->io_ptr);
+
+ if (check != length)
+ {
+ png_error(png_ptr, "Read Error");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ int check;
+ png_byte *n_data;
+ FILE *io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)n_data == data)
+ {
+ check = fread(n_data, 1, length, io_ptr);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t read, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ read = MIN(NEAR_BUF_SIZE, remaining);
+ err = fread(buf, (png_size_t)1, read, io_ptr);
+ png_memcpy(data, buf, read); /* copy far buffer to near buffer */
+ if(err != read)
+ break;
+ else
+ check += err;
+ data += read;
+ remaining -= read;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ {
+ png_error(png_ptr, "read Error");
+ }
+}
+#endif /* USE_FAR_KEYWORD */
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+static void
+png_default_flush(png_structp png_ptr)
+{
+ FILE *io_ptr;
+ io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
+ if (io_ptr != NULL)
+ fflush(io_ptr);
+}
+#endif
+
+/* This is the function that does the actual writing of data. If you are
+ not writing to a standard C stream, you should create a replacement
+ write_data function and use it at run time with png_set_write_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+static void
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+
+ check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+ png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
+ FILE *io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ near_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)near_data == data)
+ {
+ check = fwrite(near_data, 1, length, io_ptr);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t written, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ written = MIN(NEAR_BUF_SIZE, remaining);
+ png_memcpy(buf, data, written); /* copy far buffer to near buffer */
+ err = fwrite(buf, 1, written, io_ptr);
+ if (err != written)
+ break;
+ else
+ check += err;
+ data += written;
+ remaining -= written;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+
+#endif /* USE_FAR_KEYWORD */
+
+/* This function is called when there is a warning, but the library thinks
+ * it can continue anyway. Replacement functions don't have to do anything
+ * here if you don't want to. In the default configuration, png_ptr is
+ * not used, but it is passed in case it may be useful.
+ */
+static void
+png_default_warning(png_structp png_ptr, png_const_charp message)
+{
+ PNG_CONST char *name = "UNKNOWN (ERROR!)";
+ if (png_ptr != NULL && png_ptr->error_ptr != NULL)
+ name = png_ptr->error_ptr;
+ fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
+}
+
+/* This is the default error handling function. Note that replacements for
+ * this function MUST NOT RETURN, or the program will likely crash. This
+ * function is used by default, or if the program supplies NULL for the
+ * error function pointer in png_set_error_fn().
+ */
+static void
+png_default_error(png_structp png_ptr, png_const_charp message)
+{
+ png_default_warning(png_ptr, message);
+ /* We can return because png_error calls the default handler, which is
+ * actually OK in this case. */
+}
+#endif /* PNG_NO_STDIO */
+/* END of code to validate stdio-free compilation */
+
+/* START of code to validate memory allocation and deallocation */
+#ifdef PNG_USER_MEM_SUPPORTED
+
+/* Allocate memory. For reasonable files, size should never exceed
+ 64K. However, zlib may allocate more then 64K if you don't tell
+ it not to. See zconf.h and png.h for more information. zlib does
+ need to allocate exactly 64K, so whatever you call here must
+ have the ability to do that.
+
+ This piece of code can be compiled to validate max 64K allocations
+ by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
+typedef struct memory_information {
+ png_uint_32 size;
+ png_voidp pointer;
+ struct memory_information FAR *next;
+} memory_information;
+typedef memory_information FAR *memory_infop;
+
+static memory_infop pinformation = NULL;
+static int current_allocation = 0;
+static int maximum_allocation = 0;
+
+extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr,
+ png_voidp ptr));
+
+png_voidp
+png_debug_malloc(png_structp png_ptr, png_uint_32 size) {
+
+ /* png_malloc has already tested for NULL; png_create_struct calls
+ png_debug_malloc directly, with png_ptr == NULL which is OK */
+
+ if (size == 0)
+ return (png_voidp)(NULL);
+
+ /* This calls the library allocator twice, once to get the requested
+ buffer and once to get a new free list entry. */
+ {
+ memory_infop pinfo = png_malloc_default(png_ptr, sizeof *pinfo);
+ pinfo->size = size;
+ current_allocation += size;
+ if (current_allocation > maximum_allocation)
+ maximum_allocation = current_allocation;
+ pinfo->pointer = png_malloc_default(png_ptr, size);
+ pinfo->next = pinformation;
+ pinformation = pinfo;
+ /* Make sure the caller isn't assuming zeroed memory. */
+ png_memset(pinfo->pointer, 0xdd, pinfo->size);
+ return (png_voidp)(pinfo->pointer);
+ }
+}
+
+/* Free a pointer. It is removed from the list at the same time. */
+void
+png_debug_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL)
+ fprintf(STDERR, "NULL pointer to png_debug_free.\n");
+ if (ptr == 0) {
+#if 0 /* This happens all the time. */
+ fprintf(STDERR, "WARNING: freeing NULL pointer\n");
+#endif
+ return;
+ }
+
+ /* Unlink the element from the list. */
+ {
+ memory_infop FAR *ppinfo = &pinformation;
+ for (;;) {
+ memory_infop pinfo = *ppinfo;
+ if (pinfo->pointer == ptr) {
+ *ppinfo = pinfo->next;
+ current_allocation -= pinfo->size;
+ if (current_allocation < 0)
+ fprintf(STDERR, "Duplicate free of memory\n");
+ /* We must free the list element too, but first kill
+ the memory that is to be freed. */
+ memset(ptr, 0x55, pinfo->size);
+ png_free_default(png_ptr, pinfo);
+ break;
+ }
+ if (pinfo->next == NULL) {
+ fprintf(STDERR, "Pointer %x not found\n", ptr);
+ break;
+ }
+ ppinfo = &pinfo->next;
+ }
+ }
+
+ /* Finally free the data. */
+ png_free_default(png_ptr, ptr);
+}
+#endif /* PNG_USER_MEM_SUPPORTED */
+/* END of code to test memory allocation/deallocation */
+
+/* Test one file */
+int
+test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
+{
+ static FILE *fpin, *fpout; /* "static" prevents setjmp corruption */
+ png_structp read_ptr, write_ptr;
+ png_infop read_info_ptr, write_info_ptr, end_info_ptr;
+ png_bytep row_buf;
+ png_uint_32 y;
+ png_uint_32 width, height;
+ int num_pass, pass;
+ int bit_depth, color_type;
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+
+ char inbuf[256], outbuf[256];
+
+ row_buf = (png_bytep)NULL;
+
+ if ((fpin = fopen(inname, "rb")) == NULL)
+ {
+ fprintf(STDERR, "Could not find input file %s\n", inname);
+ return (1);
+ }
+
+ if ((fpout = fopen(outname, "wb")) == NULL)
+ {
+ fprintf(STDERR, "Could not open output file %s\n", outname);
+ fclose(fpin);
+ return (1);
+ }
+
+ png_debug(0, "Allocating read and write structures\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
+ (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
+#else
+ read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL);
+#endif
+#if defined(PNG_NO_STDIO)
+ png_set_error_fn(read_ptr, (png_voidp)inname, png_default_error,
+ png_default_warning);
+#endif
+#ifdef PNG_USER_MEM_SUPPORTED
+ write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
+ (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
+#else
+ write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL);
+#endif
+#if defined(PNG_NO_STDIO)
+ png_set_error_fn(write_ptr, (png_voidp)inname, png_default_error,
+ png_default_warning);
+#endif
+ png_debug(0, "Allocating read_info, write_info and end_info structures\n");
+ read_info_ptr = png_create_info_struct(read_ptr);
+ write_info_ptr = png_create_info_struct(write_ptr);
+ end_info_ptr = png_create_info_struct(read_ptr);
+#ifdef PNG_USER_MEM_SUPPORTED
+#endif
+
+ png_debug(0, "Setting jmpbuf for read struct\n");
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(read_ptr->jmpbuf))
+#endif
+ {
+ fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+ fclose(fpin);
+ fclose(fpout);
+ return (1);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(read_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+
+ png_debug(0, "Setting jmpbuf for write struct\n");
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(write_ptr->jmpbuf))
+#endif
+ {
+ fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+ fclose(fpin);
+ fclose(fpout);
+ return (1);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(write_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+
+ png_debug(0, "Initializing input and output streams\n");
+#if !defined(PNG_NO_STDIO)
+ png_init_io(read_ptr, fpin);
+ png_init_io(write_ptr, fpout);
+#else
+ png_set_read_fn(read_ptr, (png_voidp)fpin, png_default_read_data);
+ png_set_write_fn(write_ptr, (png_voidp)fpout, png_default_write_data,
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_default_flush);
+#else
+ NULL);
+#endif
+#endif
+ if(status_dots_requested == 1)
+ {
+ png_set_write_status_fn(write_ptr, write_row_callback);
+ png_set_read_status_fn(read_ptr, read_row_callback);
+ }
+ else
+ {
+ png_set_write_status_fn(write_ptr, NULL);
+ png_set_read_status_fn(read_ptr, NULL);
+ }
+
+# if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ zero_samples=0;
+ png_set_write_user_transform_fn(write_ptr, count_zero_samples);
+# endif
+
+ png_debug(0, "Reading info struct\n");
+ png_read_info(read_ptr, read_info_ptr);
+
+ png_debug(0, "Transferring info struct\n");
+ {
+ int interlace_type, compression_type, filter_type;
+
+ if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
+ &color_type, &interlace_type, &compression_type, &filter_type))
+ {
+ png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ color_type, interlace_type, compression_type, filter_type);
+#else
+ color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
+#endif
+ }
+ }
+#if defined(PNG_READ_bKGD_SUPPORTED) && defined(PNG_WRITE_bKGD_SUPPORTED)
+ {
+ png_color_16p background;
+
+ if (png_get_bKGD(read_ptr, read_info_ptr, &background))
+ {
+ png_set_bKGD(write_ptr, write_info_ptr, background);
+ }
+ }
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED)
+ {
+ double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+
+ if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
+ &red_y, &green_x, &green_y, &blue_x, &blue_y))
+ {
+ png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
+ red_y, green_x, green_y, blue_x, blue_y);
+ }
+ }
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED)
+ {
+ double gamma;
+
+ if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
+ {
+ png_set_gAMA(write_ptr, write_info_ptr, gamma);
+ }
+ }
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED) && defined(PNG_WRITE_sRGB_SUPPORTED)
+ {
+ int intent;
+
+ if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
+ {
+ png_set_sRGB(write_ptr, write_info_ptr, intent);
+ }
+ }
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED) && defined(PNG_WRITE_hIST_SUPPORTED)
+ {
+ png_uint_16p hist;
+
+ if (png_get_hIST(read_ptr, read_info_ptr, &hist))
+ {
+ png_set_hIST(write_ptr, write_info_ptr, hist);
+ }
+ }
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED)
+ {
+ png_uint_32 offset_x, offset_y;
+ int unit_type;
+
+ if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
+ {
+ png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
+ }
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED) && defined(PNG_WRITE_pCAL_SUPPORTED)
+ {
+ png_charp purpose, units;
+ png_charpp params;
+ png_int_32 X0, X1;
+ int type, nparams;
+
+ if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
+ &nparams, &units, ¶ms))
+ {
+ png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
+ nparams, units, params);
+ }
+ }
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED)
+ {
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
+ {
+ png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
+ }
+ }
+#endif
+ {
+ png_colorp palette;
+ int num_palette;
+
+ if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
+ {
+ png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
+ }
+ }
+#if defined(PNG_READ_sBIT_SUPPORTED) && defined(PNG_WRITE_sBIT_SUPPORTED)
+ {
+ png_color_8p sig_bit;
+
+ if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
+ {
+ png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
+ }
+ }
+#endif
+#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) || \
+ (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED))
+ {
+ png_textp text_ptr;
+ int num_text;
+
+ if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
+ {
+ png_debug1(0, "Handling %d tEXt/zTXt chunks\n", num_text);
+ png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
+ }
+ }
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED)
+ {
+ png_timep mod_time;
+
+ if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
+ {
+ png_set_tIME(write_ptr, write_info_ptr, mod_time);
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ /* we have to use png_strcpy instead of "=" because the string
+ pointed to by png_convert_to_rfc1123() gets free'ed before
+ we use it */
+ png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
+ tIME_chunk_present++;
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+ }
+ }
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED)
+ {
+ png_bytep trans;
+ int num_trans;
+ png_color_16p trans_values;
+
+ if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
+ &trans_values))
+ {
+ png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
+ trans_values);
+ }
+ }
+#endif
+
+ png_debug(0, "\nWriting info struct\n");
+ png_write_info(write_ptr, write_info_ptr);
+
+ png_debug(0, "\nAllocating row buffer \n");
+ row_buf = (png_bytep)png_malloc(read_ptr,
+ png_get_rowbytes(read_ptr, read_info_ptr));
+ if (row_buf == NULL)
+ {
+ fprintf(STDERR, "No memory to allocate row buffer\n");
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+ fclose(fpin);
+ fclose(fpout);
+ return (1);
+ }
+ png_debug(0, "Writing row data\n");
+
+ num_pass = png_set_interlace_handling(read_ptr);
+ png_set_interlace_handling(write_ptr);
+
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ png_debug1(0, "Writing row data for pass %d\n",pass);
+ for (y = 0; y < height; y++)
+ {
+ png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
+ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
+ }
+ }
+
+ png_debug(0, "Reading and writing end_info data\n");
+ png_read_end(read_ptr, end_info_ptr);
+ png_write_end(write_ptr, end_info_ptr);
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+ if(verbose)
+ {
+ png_uint_32 iwidth, iheight;
+ iwidth = png_get_image_width(write_ptr, write_info_ptr);
+ iheight = png_get_image_height(write_ptr, write_info_ptr);
+ fprintf(STDERR, "Image width = %lu, height = %lu\n",
+ iwidth, iheight);
+ }
+#endif
+
+ png_debug(0, "Destroying data structs\n");
+ png_free(read_ptr, row_buf);
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+
+ fclose(fpin);
+ fclose(fpout);
+
+ png_debug(0, "Opening files for comparison\n");
+ if ((fpin = fopen(inname, "rb")) == NULL)
+ {
+ fprintf(STDERR, "Could not find file %s\n", inname);
+ return (1);
+ }
+
+ if ((fpout = fopen(outname, "rb")) == NULL)
+ {
+ fprintf(STDERR, "Could not find file %s\n", outname);
+ fclose(fpin);
+ return (1);
+ }
+
+ for(;;)
+ {
+ png_size_t num_in, num_out;
+
+ num_in = fread(inbuf, 1, 1, fpin);
+ num_out = fread(outbuf, 1, 1, fpout);
+
+ if (num_in != num_out)
+ {
+ fprintf(STDERR, "Files %s and %s are of a different size\n",
+ inname, outname);
+ if(wrote_question == 0)
+ {
+ fprintf(STDERR,
+ " Was %s written with the same chunk size (8k),",inname);
+ fprintf(STDERR,
+ " filtering\n heuristic (libpng default), compression");
+ fprintf(STDERR,
+ " level (zlib default)\n and zlib version (%s)?\n\n",
+ ZLIB_VERSION);
+ wrote_question=1;
+ }
+ fclose(fpin);
+ fclose(fpout);
+ return (0);
+ }
+
+ if (!num_in)
+ break;
+
+ if (png_memcmp(inbuf, outbuf, num_in))
+ {
+ fprintf(STDERR, "Files %s and %s are different\n", inname, outname);
+ if(wrote_question == 0)
+ {
+ fprintf(STDERR,
+ " Was %s written with the same chunk size (8k),",inname);
+ fprintf(STDERR,
+ " filtering\n heuristic (libpng default), compression");
+ fprintf(STDERR,
+ " level (zlib default)\n and zlib version (%s)?\n\n",
+ ZLIB_VERSION);
+ wrote_question=1;
+ }
+ fclose(fpin);
+ fclose(fpout);
+ return (0);
+ }
+ }
+
+ fclose(fpin);
+ fclose(fpout);
+
+ return (0);
+}
+
+/* input and output filenames */
+#ifdef RISCOS
+PNG_CONST char *inname = "pngtest/png";
+PNG_CONST char *outname = "pngout/png";
+#else
+static PNG_CONST char *inname = "pngtest.png";
+static PNG_CONST char *outname = "pngout.png";
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int multiple = 0;
+ int ierror = 0;
+
+ fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
+ fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION);
+ fprintf(STDERR,"%s",png_get_copyright(NULL));
+
+ /* Do some consistency checking on the memory allocation settings, I'm
+ not sure this matters, but it is nice to know, the first of these
+ tests should be impossible because of the way the macros are set
+ in pngconf.h */
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+ fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
+#endif
+ /* I think the following can happen. */
+#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
+ fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
+#endif
+
+ if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
+ {
+ fprintf(STDERR,
+ "Warning: versions are different between png.h and png.c\n");
+ fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING);
+ fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver);
+ ++ierror;
+ }
+
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "-m") == 0)
+ {
+ multiple = 1;
+ status_dots_requested = 0;
+ }
+ else if (strcmp(argv[1], "-mv") == 0 ||
+ strcmp(argv[1], "-vm") == 0 )
+ {
+ multiple = 1;
+ verbose = 1;
+ status_dots_requested = 1;
+ }
+ else if (strcmp(argv[1], "-v") == 0)
+ {
+ verbose = 1;
+ status_dots_requested = 1;
+ inname = argv[2];
+ }
+ else
+ {
+ inname = argv[1];
+ status_dots_requested = 0;
+ }
+ }
+
+ if (!multiple && argc == 3+verbose)
+ outname = argv[2+verbose];
+
+ if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
+ {
+ fprintf(STDERR,
+ "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
+ argv[0], argv[0]);
+ fprintf(STDERR,
+ " reads/writes one PNG file (without -m) or multiple files (-m)\n");
+ fprintf(STDERR,
+ " with -m %s is used as a temporary file\n", outname);
+ exit(1);
+ }
+
+ if (multiple)
+ {
+ int i;
+#ifdef PNG_USER_MEM_SUPPORTED
+ int allocation_now = current_allocation;
+#endif
+ for (i=2; i<argc; ++i)
+ {
+ int kerror;
+ fprintf(STDERR, "Testing %s:",argv[i]);
+ kerror = test_one_file(argv[i], outname);
+ if (kerror == 0)
+ {
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ fprintf(STDERR, " PASS (%lu zero samples)\n",zero_samples);
+#else
+ fprintf(STDERR, " PASS\n");
+#endif
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ if(tIME_chunk_present != 0)
+ fprintf(STDERR, " tIME = %s\n",tIME_string);
+ tIME_chunk_present = 0;
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+ }
+ else
+ {
+ fprintf(STDERR, " FAIL\n");
+ ierror += kerror;
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (allocation_now != current_allocation)
+ fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
+ current_allocation-allocation_now);
+ if (current_allocation != 0) {
+ memory_infop pinfo = pinformation;
+
+ fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
+ current_allocation);
+ while (pinfo != NULL) {
+ fprintf(STDERR, " %d bytes at %x\n", pinfo->size, pinfo->pointer);
+ pinfo = pinfo->next;
+ }
+ }
+#endif
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ fprintf(STDERR, "Maximum memory allocation: %d bytes\n",
+ maximum_allocation);
+#endif
+ }
+ else
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ int kerror;
+#ifdef PNG_USER_MEM_SUPPORTED
+ int allocation_now = current_allocation;
+#endif
+ if (i == 1) status_dots_requested = 1;
+ else if(verbose == 0)status_dots_requested = 0;
+ if (i == 0 || verbose == 1 || ierror != 0)
+ fprintf(STDERR, "Testing %s:",inname);
+ kerror = test_one_file(inname, outname);
+ if(kerror == 0)
+ {
+ if(verbose == 1 || i == 2)
+ {
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ fprintf(STDERR, " PASS (%lu zero samples)\n",zero_samples);
+#else
+ fprintf(STDERR, " PASS\n");
+#endif
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ if(tIME_chunk_present != 0)
+ fprintf(STDERR, " tIME = %s\n",tIME_string);
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+ }
+ }
+ else
+ {
+ if(verbose == 0 && i != 2)
+ fprintf(STDERR, "Testing %s:",inname);
+ fprintf(STDERR, " FAIL\n");
+ ierror += kerror;
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (allocation_now != current_allocation)
+ fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
+ current_allocation-allocation_now);
+ if (current_allocation != 0) {
+ memory_infop pinfo = pinformation;
+
+ fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
+ current_allocation);
+ while (pinfo != NULL) {
+ fprintf(STDERR, " %d bytes at %x\n", pinfo->size, pinfo->pointer);
+ pinfo = pinfo->next;
+ }
+ }
+#endif
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ fprintf(STDERR, "Maximum memory allocation: %d bytes\n",
+ maximum_allocation);
+#endif
+ }
+
+ if (ierror == 0)
+ fprintf(STDERR, "libpng passes test\n");
+ else
+ fprintf(STDERR, "libpng FAILS test\n");
+ return (int)(ierror != 0);
+}
+
--- /dev/null
+
+/* pngtrans.c - transforms the data in a row (used by both readers and writers)
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* turn on bgr to rgb mapping */
+void
+png_set_bgr(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_bgr\n");
+ png_ptr->transformations |= PNG_BGR;
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* turn on 16 bit byte swapping */
+void
+png_set_swap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap\n");
+ if (png_ptr->bit_depth == 16)
+ png_ptr->transformations |= PNG_SWAP_BYTES;
+}
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* turn on pixel packing */
+void
+png_set_packing(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packing\n");
+ if (png_ptr->bit_depth < 8)
+ {
+ png_ptr->transformations |= PNG_PACK;
+ png_ptr->usr_bit_depth = 8;
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* turn on packed pixel swapping */
+void
+png_set_packswap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packswap\n");
+ if (png_ptr->bit_depth < 8)
+ png_ptr->transformations |= PNG_PACKSWAP;
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+void
+png_set_shift(png_structp png_ptr, png_color_8p true_bits)
+{
+ png_debug(1, "in png_set_shift\n");
+ png_ptr->transformations |= PNG_SHIFT;
+ png_ptr->shift = *true_bits;
+}
+#endif
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+int
+png_set_interlace_handling(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_interlace handling\n");
+ if (png_ptr->interlaced)
+ {
+ png_ptr->transformations |= PNG_INTERLACE;
+ return (7);
+ }
+
+ return (1);
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte on read, or remove a filler or alpha byte on write.
+ * The filler type has changed in v0.95 to allow future 2-byte fillers
+ * for 48-bit input data, as well as to avoid problems with some compilers
+ * that don't like bytes as parameters.
+ */
+void
+png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
+{
+ png_debug(1, "in png_set_filler\n");
+ png_ptr->transformations |= PNG_FILLER;
+ png_ptr->filler = (png_byte)filler;
+ if (filler_loc == PNG_FILLER_AFTER)
+ png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
+ else
+ png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
+
+ /* This should probably go in the "do_filler" routine.
+ * I attempted to do that in libpng-1.0.1a but that caused problems
+ * so I restored it in libpng-1.0.2a
+ */
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_ptr->usr_channels = 4;
+ }
+
+ /* Also I added this in libpng-1.0.2a (what happens when we expand
+ * a less-than-8-bit grayscale to GA? */
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8)
+ {
+ png_ptr->usr_channels = 2;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void
+png_set_swap_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap_alpha\n");
+ png_ptr->transformations |= PNG_SWAP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+void
+png_set_invert_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_invert_alpha\n");
+ png_ptr->transformations |= PNG_INVERT_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+void
+png_set_invert_mono(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_invert_mono\n");
+ png_ptr->transformations |= PNG_INVERT_MONO;
+}
+
+/* invert monochrome grayscale data */
+void
+png_do_invert(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_invert\n");
+ if (row_info->bit_depth == 1 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(~(*rp));
+ rp++;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* swaps byte order on 16 bit depth images */
+void
+png_do_swap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_swap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->bit_depth == 16)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop= row_info->width * row_info->channels;
+
+ for (i = 0; i < istop; i++, rp += 2)
+ {
+ png_byte t = *rp;
+ *rp = *(rp + 1);
+ *(rp + 1) = t;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+static png_byte onebppswaptable[256] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+static png_byte twobppswaptable[256] = {
+ 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
+ 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
+ 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
+ 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
+ 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
+ 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
+ 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
+ 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
+ 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
+ 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
+ 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
+ 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
+ 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
+ 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
+ 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
+ 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
+ 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
+ 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
+ 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
+ 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
+ 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
+ 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
+ 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
+ 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
+ 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
+ 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
+ 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
+ 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
+ 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
+ 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
+ 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
+ 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
+};
+
+static png_byte fourbppswaptable[256] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
+ 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
+ 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
+ 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
+ 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
+ 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
+ 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
+ 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
+ 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
+ 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
+ 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
+ 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
+ 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
+ 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
+ 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
+ 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
+ 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
+ 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
+ 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
+ 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
+ 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
+ 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
+ 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
+ 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
+ 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
+ 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
+ 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
+ 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
+ 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
+ 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
+ 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
+};
+
+/* swaps pixel packing order within bytes */
+void
+png_do_packswap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_packswap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->bit_depth < 8)
+ {
+ png_bytep rp, end, table;
+
+ end = row + row_info->rowbytes;
+
+ if (row_info->bit_depth == 1)
+ table = onebppswaptable;
+ else if (row_info->bit_depth == 2)
+ table = twobppswaptable;
+ else if (row_info->bit_depth == 4)
+ table = fourbppswaptable;
+ else
+ return;
+
+ for (rp = row; rp < end; rp++)
+ *rp = table[*rp];
+ }
+}
+#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+/* remove filler or alpha byte(s) */
+void
+png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags)
+{
+ png_debug(1, "in png_do_strip_filler\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+/*
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB ||
+ row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+*/
+ png_bytep sp=row;
+ png_bytep dp=row;
+ png_uint_32 row_width=row_info->width;
+ png_uint_32 i;
+
+ if (row_info->channels == 4)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from RGBX or RGBA to RGB */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ dp+=3; sp+=4;
+ for (i = 1; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XRGB or ARGB to RGB */
+ else
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_width * 3;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
+ sp += 8; dp += 6;
+ for (i = 1; i < row_width; i++)
+ {
+ /* This could be (although memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
+ for (i = 0; i < row_width; i++)
+ {
+ /* This could be (although memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+ sp+=2;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 48;
+ row_info->rowbytes = row_width * 6;
+ }
+ row_info->channels = 3;
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ }
+/*
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY ||
+ row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+*/
+ else if (row_info->channels == 2)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from GX or GA to G */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XG or AG to G */
+ else
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ /* This converts from GGXX or GGAA to GG */
+ sp += 4; dp += 2;
+ for (i = 1; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ /* This converts from XXGG or AAGG to GG */
+ for (i = 0; i < row_width; i++)
+ {
+ sp += 2;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ row_info->channels = 1;
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* swaps red and blue bytes within a pixel */
+void
+png_do_bgr(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_bgr\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 3)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 4)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 6)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 4);
+ *(rp + 4) = save;
+ save = *(rp + 1);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 5) = save;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 8)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 4);
+ *(rp + 4) = save;
+ save = *(rp + 1);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 5) = save;
+ }
+ }
+ }
+ }
+}
+#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
+
--- /dev/null
+
+/* pngwio.c - functions for data output
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ *
+ * This file provides a location for all output. Users who need
+ * special handling are expected to write functions that have the same
+ * arguments as these and perform similar functions, but that possibly
+ * use different output methods. Note that you shouldn't change these
+ * functions, but rather write replacement functions and then change
+ * them at run time with png_set_write_fn(...).
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Write the data to whatever output you are using. The default routine
+ writes to a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered writes. This should never be asked
+ to write more than 64K on a 16 bit machine. */
+
+void
+png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ if (png_ptr->write_data_fn != NULL )
+ (*(png_ptr->write_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL write function");
+}
+
+#if !defined(PNG_NO_STDIO)
+/* This is the function that does the actual writing of data. If you are
+ not writing to a standard C stream, you should create a replacement
+ write_data function and use it at run time with png_set_write_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+#ifdef __VISAGECPP__
+static void _Optlink
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+#else
+static void
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+#endif
+{
+ png_uint_32 check;
+
+ check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+#ifdef __VISAGECPP__
+static void _Optlink
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+#else
+static void
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+#endif
+{
+ png_uint_32 check;
+ png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
+ FILE *io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ near_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)near_data == data)
+ {
+ check = fwrite(near_data, 1, length, io_ptr);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t written, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ written = MIN(NEAR_BUF_SIZE, remaining);
+ png_memcpy(buf, data, written); /* copy far buffer to near buffer */
+ err = fwrite(buf, 1, written, io_ptr);
+ if (err != written)
+ break;
+ else
+ check += err;
+ data += written;
+ remaining -= written;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+
+#endif
+#endif
+
+/* This function is called to output any data pending writing (normally
+ to disk). After png_flush is called, there should be no data pending
+ writing in any buffers. */
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+void
+png_flush(png_structp png_ptr)
+{
+ if (png_ptr->output_flush_fn != NULL)
+ (*(png_ptr->output_flush_fn))(png_ptr);
+}
+
+#if !defined(PNG_NO_STDIO)
+#ifdef __VISAGECPP__
+static void _Optlink
+png_default_flush(png_structp png_ptr)
+#else
+static void
+png_default_flush(png_structp png_ptr)
+#endif
+{
+ FILE *io_ptr;
+ io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
+ if (io_ptr != NULL)
+ fflush(io_ptr);
+}
+#endif
+#endif
+
+/* This function allows the application to supply new output functions for
+ libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png output data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the output functions. May be NULL.
+ write_data_fn - pointer to a new output function that takes as its
+ arguments a pointer to a png_struct, a pointer to
+ data to be written, and a 32-bit unsigned int that is
+ the number of bytes to be written. The new write
+ function should call png_error(png_ptr, "Error msg")
+ to exit and output any fatal error messages.
+ flush_data_fn - pointer to a new flush function that takes as its
+ arguments a pointer to a png_struct. After a call to
+ the flush function, there should be no data in any buffers
+ or pending transmission. If the output method doesn't do
+ any buffering of ouput, a function prototype must still be
+ supplied although it doesn't have to do anything. If
+ PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile
+ time, output_flush_fn will be ignored, although it must be
+ supplied for compatibility. */
+void
+png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
+{
+ png_ptr->io_ptr = io_ptr;
+
+#if !defined(PNG_NO_STDIO)
+ if (write_data_fn != NULL)
+ png_ptr->write_data_fn = write_data_fn;
+ else
+ png_ptr->write_data_fn = png_default_write_data;
+#else
+ png_ptr->write_data_fn = write_data_fn;
+#endif
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#if !defined(PNG_NO_STDIO)
+ if (output_flush_fn != NULL)
+ png_ptr->output_flush_fn = output_flush_fn;
+ else
+ png_ptr->output_flush_fn = png_default_flush;
+#else
+ png_ptr->output_flush_fn = output_flush_fn;
+#endif
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+ /* It is an error to read while writing a png file */
+ if (png_ptr->read_data_fn != NULL)
+ {
+ png_ptr->read_data_fn = NULL;
+ png_warning(png_ptr,
+ "Attempted to set both read_data_fn and write_data_fn in");
+ png_warning(png_ptr,
+ "the same structure. Resetting read_data_fn to NULL.");
+ }
+}
+
+#if defined(USE_FAR_KEYWORD)
+#if defined(_MSC_VER)
+void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ FP_OFF(near_ptr) = FP_OFF(ptr);
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(FP_SEG(ptr) != FP_SEG(far_ptr))
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# else
+void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ near_ptr = (void FAR *)ptr;
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(far_ptr != ptr)
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# endif
+# endif
--- /dev/null
+
+/* pngwrite.c - general routines to write a PNG file
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ */
+
+/* get internal access to png.h */
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Writes all the PNG information. This is the suggested way to use the
+ * library. If you have a new chunk to add, make a function to write it,
+ * and put it in the correct location here. If you want the chunk written
+ * after the image data, put it in png_write_end(). I strongly encourage
+ * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
+ * the chunk, as that will keep the code from breaking if you want to just
+ * write a plain PNG file. If you have long comments, I suggest writing
+ * them in png_write_end(), and compressing them.
+ */
+void
+png_write_info(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ int i;
+#endif
+
+ png_debug(1, "in png_write_info\n");
+ png_write_sig(png_ptr); /* write PNG signature */
+ /* write IHDR information. */
+ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
+ info_ptr->filter_type,
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ info_ptr->interlace_type);
+#else
+ 0);
+#endif
+ /* the rest of these check to see if the valid field has the appropriate
+ flag set, and if it does, writes the chunk. */
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_gAMA)
+ png_write_gAMA(png_ptr, info_ptr->gamma);
+#endif
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
+#endif
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sBIT)
+ png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_cHRM)
+ png_write_cHRM(png_ptr,
+ info_ptr->x_white, info_ptr->y_white,
+ info_ptr->x_red, info_ptr->y_red,
+ info_ptr->x_green, info_ptr->y_green,
+ info_ptr->x_blue, info_ptr->y_blue);
+#endif
+ if (info_ptr->valid & PNG_INFO_PLTE)
+ png_write_PLTE(png_ptr, info_ptr->palette,
+ (png_uint_32)info_ptr->num_palette);
+ else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_error(png_ptr, "Valid palette required for paletted images\n");
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tRNS)
+ {
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ /* invert the alpha channel (in tRNS) */
+ if (png_ptr->transformations & PNG_INVERT_ALPHA &&
+ info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int j;
+ for (j=0; j<(int)info_ptr->num_trans; j++)
+ info_ptr->trans[j] = 255 - info_ptr->trans[j];
+ }
+#endif
+ png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
+ info_ptr->num_trans, info_ptr->color_type);
+ }
+#endif
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_bKGD)
+ png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_hIST)
+ png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
+#endif
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
+ info_ptr->offset_unit_type);
+#endif
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pCAL)
+ png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
+ info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
+ info_ptr->pcal_units, info_ptr->pcal_params);
+#endif
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
+ info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
+#endif
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tIME)
+ {
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+ png_ptr->flags |= PNG_FLAG_WROTE_tIME;
+ }
+#endif
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* Check to see if we need to write text chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing header text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ /* If we want a compressed text chunk */
+ if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+}
+
+/* Writes the end of the PNG file. If you don't want to write comments or
+ * time information, you can pass NULL for info. If you already wrote these
+ * in png_write_info(), do not write them again here. If you have long
+ * comments, I suggest writing them here, and compressing them.
+ */
+void
+png_write_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_write_end\n");
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "No IDATs written into file");
+
+ /* see if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ int i; /* local index variable */
+#endif
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ /* check to see if user has supplied a time chunk */
+ if (info_ptr->valid & PNG_INFO_tIME &&
+ !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+#endif
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* loop through comment chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, info_ptr->text[i].text_length);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text\n");
+#endif
+
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ /* write end of PNG file */
+ png_write_IEND(png_ptr);
+}
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+void
+png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
+{
+ png_debug(1, "in png_convert_from_struct_tm\n");
+ ptime->year = (png_uint_16)(1900 + ttime->tm_year);
+ ptime->month = (png_byte)(ttime->tm_mon + 1);
+ ptime->day = (png_byte)ttime->tm_mday;
+ ptime->hour = (png_byte)ttime->tm_hour;
+ ptime->minute = (png_byte)ttime->tm_min;
+ ptime->second = (png_byte)ttime->tm_sec;
+}
+
+void
+png_convert_from_time_t(png_timep ptime, time_t ttime)
+{
+ struct tm *tbuf;
+
+ png_debug(1, "in png_convert_from_time_t\n");
+ tbuf = gmtime(&ttime);
+ png_convert_from_struct_tm(ptime, tbuf);
+}
+#endif
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+png_structp
+png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, NULL, NULL, NULL));
+}
+
+/* Alternate initialize png_ptr structure, and allocate any memory needed */
+png_structp
+png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_structp png_ptr;
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+ png_debug(1, "in png_create_write_struct\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
+ (png_malloc_ptr)malloc_fn)) == NULL)
+#else
+ if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
+#endif /* PNG_USER_MEM_SUPPORTED */
+ {
+ return ((png_structp)NULL);
+ }
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_destroy_struct(png_ptr);
+ return ((png_structp)NULL);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (png_libpng_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+ 1, NULL, NULL);
+#endif
+
+ return ((png_structp)png_ptr);
+}
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+void
+png_write_init(png_structp png_ptr)
+{
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+
+ png_debug(1, "in png_write_init\n");
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+ 1, NULL, NULL);
+#endif
+}
+
+/* Write a few rows of image data. If the image is interlaced,
+ * either you will have to write the 7 sub images, or, if you
+ * have called png_set_interlace_handling(), you will have to
+ * "write" the image seven times.
+ */
+void
+png_write_rows(png_structp png_ptr, png_bytepp row,
+ png_uint_32 num_rows)
+{
+ png_uint_32 i; /* row counter */
+ png_bytepp rp; /* row pointer */
+
+ png_debug(1, "in png_write_rows\n");
+ /* loop through the rows */
+ for (i = 0, rp = row; i < num_rows; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+}
+
+/* Write the image. You only need to call this function once, even
+ * if you are writing an interlaced image.
+ */
+void
+png_write_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i; /* row index */
+ int pass, num_pass; /* pass variables */
+ png_bytepp rp; /* points to current row */
+
+ png_debug(1, "in png_write_image\n");
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* intialize interlace handling. If image is not interlaced,
+ this will set pass to 1 */
+ num_pass = png_set_interlace_handling(png_ptr);
+#else
+ num_pass = 1;
+#endif
+ /* loop through passes */
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ /* loop through image */
+ for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+ }
+}
+
+/* called by user to write a row of image data */
+void
+png_write_row(png_structp png_ptr, png_bytep row)
+{
+ png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
+ png_ptr->row_number, png_ptr->pass);
+ /* initialize transformations and other stuff if first time */
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ /* check for transforms that have been set but were defined out */
+#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
+#endif
+
+ png_write_start_row(png_ptr);
+ }
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* if interlaced and not interested in row, return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 7)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 7) || png_ptr->width < 5)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 7) != 4)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 3) || png_ptr->width < 3)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 3) != 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 1) || png_ptr->width < 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 1))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ /* set up row info for transformations */
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->usr_width;
+ png_ptr->row_info.channels = png_ptr->usr_channels;
+ png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
+ png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
+ png_ptr->row_info.channels);
+
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
+ png_debug1(3, "row_info->width = %d\n", png_ptr->row_info.width);
+ png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
+ png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
+ png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
+ png_debug1(3, "row_info->rowbytes = %d\n", png_ptr->row_info.rowbytes);
+
+ /* Copy user's row into buffer, leaving room for filter byte. */
+ png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
+ png_ptr->row_info.rowbytes);
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* handle interlacing */
+ if (png_ptr->interlaced && png_ptr->pass < 6 &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_do_write_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass);
+ /* this should always get caught above, but still ... */
+ if (!(png_ptr->row_info.width))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ }
+#endif
+
+ /* handle other transformations */
+ if (png_ptr->transformations)
+ png_do_write_transformations(png_ptr);
+
+ /* Find a filter if necessary, filter the row and write it out. */
+ png_write_find_filter(png_ptr, &(png_ptr->row_info));
+
+ if (png_ptr->write_row_fn != NULL)
+ (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
+}
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set the automatic flush interval or 0 to turn flushing off */
+void
+png_set_flush(png_structp png_ptr, int nrows)
+{
+ png_debug(1, "in png_set_flush\n");
+ png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
+}
+
+/* flush the current output buffers now */
+void
+png_write_flush(png_structp png_ptr)
+{
+ int wrote_IDAT;
+
+ png_debug(1, "in png_write_flush\n");
+ /* We have already written out all of the data */
+ if (png_ptr->row_number >= png_ptr->num_rows)
+ return;
+
+ do
+ {
+ int ret;
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
+ wrote_IDAT = 0;
+
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ wrote_IDAT = 1;
+ }
+ } while(wrote_IDAT == 1);
+
+ /* If there is any data left to be output, write it into a new IDAT */
+ if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ png_ptr->flush_rows = 0;
+ png_flush(png_ptr);
+}
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+/* free all memory used by the write */
+void
+png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn = NULL;
+#endif
+
+ png_debug(1, "in png_destroy_write_struct\n");
+ if (png_ptr_ptr != NULL)
+ {
+ png_ptr = *png_ptr_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+ }
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+#ifdef PNG_WRITE_tEXt_SUPPORTED
+ png_free(png_ptr, info_ptr->text);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ png_free(png_ptr, info_ptr->pcal_purpose);
+ png_free(png_ptr, info_ptr->pcal_units);
+ if (info_ptr->pcal_params != NULL)
+ {
+ int i;
+ for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
+ {
+ png_free(png_ptr, info_ptr->pcal_params[i]);
+ }
+ png_free(png_ptr, info_ptr->pcal_params);
+ }
+#endif
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, free_fn);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+ png_write_destroy(png_ptr);
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)png_ptr, free_fn);
+#else
+ png_destroy_struct((png_voidp)png_ptr);
+#endif
+ *png_ptr_ptr = (png_structp)NULL;
+ }
+}
+
+
+/* Free any memory used in png_ptr struct (old method) */
+void
+png_write_destroy(png_structp png_ptr)
+{
+ jmp_buf tmp_jmp; /* save jump buffer */
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn;
+#endif
+
+ png_debug(1, "in png_write_destroy\n");
+ /* free any memory zlib uses */
+ deflateEnd(&png_ptr->zstream);
+
+ /* free our memory. png_free checks NULL for us. */
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+ png_free(png_ptr, png_ptr->sub_row);
+ png_free(png_ptr, png_ptr->up_row);
+ png_free(png_ptr, png_ptr->avg_row);
+ png_free(png_ptr, png_ptr->paeth_row);
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_free(png_ptr, png_ptr->time_buffer);
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_free(png_ptr, png_ptr->prev_filters);
+ png_free(png_ptr, png_ptr->filter_weights);
+ png_free(png_ptr, png_ptr->inv_filter_weights);
+ png_free(png_ptr, png_ptr->filter_costs);
+ png_free(png_ptr, png_ptr->inv_filter_costs);
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+ /* reset structure */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr->free_fn = free_fn;
+#endif
+
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+}
+
+/* Allow the application to select one or more row filters to use. */
+void
+png_set_filter(png_structp png_ptr, int method, int filters)
+{
+ png_debug(1, "in png_set_filter\n");
+ /* We allow 'method' only for future expansion of the base filter method. */
+ if (method == PNG_FILTER_TYPE_BASE)
+ {
+ switch (filters & (PNG_ALL_FILTERS | 0x07))
+ {
+ case 5:
+ case 6:
+ case 7: png_warning(png_ptr, "Unknown row filter for method 0");
+ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break;
+ case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break;
+ case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break;
+ case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break;
+ case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
+ default: png_ptr->do_filter = (png_byte)filters; break;
+ }
+
+ /* If we have allocated the row_buf, this means we have already started
+ * with the image and we should have allocated all of the filter buffers
+ * that have been selected. If prev_row isn't already allocated, then
+ * it is too late to start using the filters that need it, since we
+ * will be missing the data in the previous row. If an application
+ * wants to start and stop using particular filters during compression,
+ * it should start out with all of the filters, and then add and
+ * remove them after the start of compression.
+ */
+ if (png_ptr->row_buf != NULL)
+ {
+ if (png_ptr->do_filter & PNG_FILTER_SUB && png_ptr->sub_row == NULL)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_UP && png_ptr->up_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Up filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_UP;
+ }
+ else
+ {
+ png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_AVG && png_ptr->avg_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Average filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_AVG;
+ }
+ else
+ {
+ png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_PAETH &&
+ png_ptr->paeth_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Paeth filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_PAETH;
+ }
+ else
+ {
+ png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+ }
+
+ if (png_ptr->do_filter == PNG_NO_FILTERS)
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ }
+ }
+ else
+ png_error(png_ptr, "Unknown custom filter method");
+}
+
+/* This allows us to influence the way in which libpng chooses the "best"
+ * filter for the current scanline. While the "minimum-sum-of-absolute-
+ * differences metric is relatively fast and effective, there is some
+ * question as to whether it can be improved upon by trying to keep the
+ * filtered data going to zlib more consistent, hopefully resulting in
+ * better compression.
+ */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
+void
+png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
+ int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs)
+{
+ int i;
+
+ png_debug(1, "in png_set_filter_heuristics\n");
+ if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
+ {
+ png_warning(png_ptr, "Unknown filter heuristic method");
+ return;
+ }
+
+ if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
+ {
+ heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
+ }
+
+ if (num_weights < 0 || filter_weights == NULL ||
+ heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
+ {
+ num_weights = 0;
+ }
+
+ png_ptr->num_prev_filters = num_weights;
+ png_ptr->heuristic_method = heuristic_method;
+
+ if (num_weights > 0)
+ {
+ if (png_ptr->prev_filters == NULL)
+ {
+ png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_byte) * num_weights));
+
+ /* To make sure that the weighting starts out fairly */
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->prev_filters[i] = 255;
+ }
+ }
+
+ if (png_ptr->filter_weights == NULL)
+ {
+ png_ptr->filter_weights = (png_uint_16p) png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * num_weights));
+
+ png_ptr->inv_filter_weights = (png_uint_16p) png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * num_weights));
+
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ }
+
+ for (i = 0; i < num_weights; i++)
+ {
+ if (filter_weights[i] < 0.0)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ else
+ {
+ png_ptr->inv_filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
+ png_ptr->filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
+ }
+ }
+ }
+
+ /* If, in the future, there are other filter methods, this would
+ * need to be based on png_ptr->filter.
+ */
+ if (png_ptr->filter_costs == NULL)
+ {
+ png_ptr->filter_costs = (png_uint_16p) png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
+
+ png_ptr->inv_filter_costs = (png_uint_16p) png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
+
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ }
+
+ /* Here is where we set the relative costs of the different filters. We
+ * should take the desired compression level into account when setting
+ * the costs, so that Paeth, for instance, has a high relative cost at low
+ * compression levels, while it has a lower relative cost at higher
+ * compression settings. The filter types are in order of increasing
+ * relative cost, so it would be possible to do this with an algorithm.
+ */
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ if (filter_costs == NULL || filter_costs[i] < 0.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ else if (filter_costs[i] >= 1.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
+ png_ptr->filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
+ }
+ }
+}
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+void
+png_set_compression_level(png_structp png_ptr, int level)
+{
+ png_debug(1, "in png_set_compression_level\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
+ png_ptr->zlib_level = level;
+}
+
+void
+png_set_compression_mem_level(png_structp png_ptr, int mem_level)
+{
+ png_debug(1, "in png_set_compression_mem_level\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
+ png_ptr->zlib_mem_level = mem_level;
+}
+
+void
+png_set_compression_strategy(png_structp png_ptr, int strategy)
+{
+ png_debug(1, "in png_set_compression_strategy\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
+ png_ptr->zlib_strategy = strategy;
+}
+
+void
+png_set_compression_window_bits(png_structp png_ptr, int window_bits)
+{
+ if (window_bits > 15)
+ png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
+ png_ptr->zlib_window_bits = window_bits;
+}
+
+void
+png_set_compression_method(png_structp png_ptr, int method)
+{
+ png_debug(1, "in png_set_compression_method\n");
+ if (method != 8)
+ png_warning(png_ptr, "Only compression method 8 is supported by PNG");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
+ png_ptr->zlib_method = method;
+}
+
+void
+png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
+{
+ png_ptr->write_row_fn = write_row_fn;
+}
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+void
+png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
+ write_user_transform_fn)
+{
+ png_debug(1, "in png_set_write_user_transform_fn\n");
+ png_ptr->transformations |= PNG_USER_TRANSFORM;
+ png_ptr->write_user_transform_fn = write_user_transform_fn;
+}
+#endif
+
--- /dev/null
+
+/* pngwtran.c - transforms the data in a row for PNG writers
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Transform the data according to the user's wishes. The order of
+ * transformations is significant.
+ */
+void
+png_do_write_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_write_transformations\n");
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ if (png_ptr->transformations & PNG_USER_TRANSFORM)
+ if(png_ptr->write_user_transform_fn != NULL)
+ (*(png_ptr->write_user_transform_fn)) /* user write transform function */
+ (png_ptr, /* png_ptr */
+ &(png_ptr->row_info), /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* png_uint_32 rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
+#endif
+#if defined(PNG_WRITE_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->flags);
+#endif
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->bit_depth);
+#endif
+#if defined(PNG_WRITE_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+}
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
+ * row_info bit depth should be 8 (one pixel per byte). The channels
+ * should be 1 (this only happens on grayscale and paletted images).
+ */
+void
+png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
+{
+ png_debug(1, "in png_do_pack\n");
+ if (row_info->bit_depth == 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->channels == 1)
+ {
+ switch ((int)bit_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int mask, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ mask = 0x80;
+ v = 0;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (*sp != 0)
+ v |= mask;
+ sp++;
+ if (mask > 1)
+ mask >>= 1;
+ else
+ {
+ mask = 0x80;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ }
+ if (mask != 0x80)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ shift = 6;
+ v = 0;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0x3);
+ v |= (value << shift);
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 2;
+ sp++;
+ }
+ if (shift != 6)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ shift = 4;
+ v = 0;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0xf);
+ v |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 4;
+
+ sp++;
+ }
+ if (shift != 4)
+ *dp = (png_byte)v;
+ break;
+ }
+ }
+ row_info->bit_depth = (png_byte)bit_depth;
+ row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
+ row_info->rowbytes =
+ ((row_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Shift pixel values to take advantage of whole range. Pass the
+ * true number of bits in bit_depth. The row should be packed
+ * according to row_info->bit_depth. Thus, if you had a row of
+ * bit depth 4, but the pixels only had values from 0 to 7, you
+ * would pass 3 as bit_depth, and this routine would translate the
+ * data to 0 to 15.
+ */
+void
+png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
+{
+ png_debug(1, "in png_do_shift\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL &&
+#else
+ if (
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift_start[4], shift_dec[4];
+ int channels = 0;
+
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->red;
+ shift_dec[channels] = bit_depth->red;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->green;
+ shift_dec[channels] = bit_depth->green;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->blue;
+ shift_dec[channels] = bit_depth->blue;
+ channels++;
+ }
+ else
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->gray;
+ shift_dec[channels] = bit_depth->gray;
+ channels++;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
+ shift_dec[channels] = bit_depth->alpha;
+ channels++;
+ }
+
+ /* with low row depths, could only be grayscale, so one channel */
+ if (row_info->bit_depth < 8)
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_byte mask;
+ png_uint_32 row_bytes = row_info->rowbytes;
+
+ if (bit_depth->gray == 1 && row_info->bit_depth == 2)
+ mask = 0x55;
+ else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
+ mask = 0x11;
+ else
+ mask = 0xff;
+
+ for (i = 0; i < row_bytes; i++, bp++)
+ {
+ png_uint_16 v;
+ int j;
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & mask);
+ }
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_info->width;
+
+ for (i = 0; i < istop; i++, bp++)
+ {
+
+ png_uint_16 v;
+ int j;
+ int c = (int)(i%channels);
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & 0xff);
+ }
+ }
+ }
+ else
+ {
+ png_bytep bp;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_info->width;
+
+ for (bp = row, i = 0; i < istop; i++)
+ {
+ int c = (int)(i%channels);
+ png_uint_16 value, v;
+ int j;
+
+ v = ((png_uint_16)(*bp) << 8) + *(bp + 1);
+ value = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
+ else
+ value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
+ }
+ *bp++ = (png_byte)(value >> 8);
+ *bp++ = (png_byte)(value & 0xff);
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void
+png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from ARGB to RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AARRGGBB to RRGGBBAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save[2];
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from AG to GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AAGG to GGAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save[2];
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+void
+png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_invert_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This inverts the alpha channel in RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = 255 - *(sp++);
+ }
+ }
+ /* This inverts the alpha channel in RRGGBBAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = 255 - *(sp++);
+ *(dp++) = 255 - *(sp++);
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This inverts the alpha channel in GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = 255 - *(sp++);
+ }
+ }
+ /* This inverts the alpha channel in GGAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = 255 - *(sp++);
+ *(dp++) = 255 - *(sp++);
+ }
+ }
+ }
+ }
+}
+#endif
--- /dev/null
+
+/* pngwutil.c - utilities to write a PNG file
+ *
+ * libpng 1.0.3 - January 14, 1999
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Place a 32-bit number into a buffer in PNG byte order. We work
+ * with unsigned numbers for convenience, although one supported
+ * ancillary chunk uses signed (two's complement) numbers.
+ */
+void
+png_save_uint_32(png_bytep buf, png_uint_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* The png_save_int_32 function assumes integers are stored in two's
+ * complement format. If this isn't the case, then this routine needs to
+ * be modified to write data in two's complement format.
+ */
+void
+png_save_int_32(png_bytep buf, png_int_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+#endif
+
+/* Place a 16-bit number into a buffer in PNG byte order.
+ * The parameter is declared unsigned int, not png_uint_16,
+ * just to avoid potential problems on pre-ANSI C compilers.
+ */
+void
+png_save_uint_16(png_bytep buf, unsigned int i)
+{
+ buf[0] = (png_byte)((i >> 8) & 0xff);
+ buf[1] = (png_byte)(i & 0xff);
+}
+
+/* Write a PNG chunk all at once. The type is an array of ASCII characters
+ * representing the chunk name. The array must be at least 4 bytes in
+ * length, and does not need to be null terminated. To be safe, pass the
+ * pre-defined chunk names here, and if you need a new one, define it
+ * where the others are defined. The length is the length of the data.
+ * All the data must be present. If that is not possible, use the
+ * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
+ * functions instead.
+ */
+void
+png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
+ png_bytep data, png_size_t length)
+{
+ png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
+ png_write_chunk_data(png_ptr, data, length);
+ png_write_chunk_end(png_ptr);
+}
+
+/* Write the start of a PNG chunk. The type is the chunk type.
+ * The total_length is the sum of the lengths of all the data you will be
+ * passing in png_write_chunk_data().
+ */
+void
+png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
+ png_uint_32 length)
+{
+ png_byte buf[4];
+ png_debug2(0, "Writing %s chunk (%d bytes)\n", chunk_name, length);
+
+ /* write the length */
+ png_save_uint_32(buf, length);
+ png_write_data(png_ptr, buf, (png_size_t)4);
+
+ /* write the chunk name */
+ png_write_data(png_ptr, chunk_name, (png_size_t)4);
+ /* reset the crc and run it over the chunk name */
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
+}
+
+/* Write the data of a PNG chunk started with png_write_chunk_start().
+ * Note that multiple calls to this function are allowed, and that the
+ * sum of the lengths from these calls *must* add up to the total_length
+ * given to png_write_chunk_start().
+ */
+void
+png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ /* write the data, and run the CRC over it */
+ if (data != NULL && length > 0)
+ {
+ png_calculate_crc(png_ptr, data, length);
+ png_write_data(png_ptr, data, length);
+ }
+}
+
+/* Finish a chunk started with png_write_chunk_start(). */
+void
+png_write_chunk_end(png_structp png_ptr)
+{
+ png_byte buf[4];
+
+ /* write the crc */
+ png_save_uint_32(buf, png_ptr->crc);
+
+ png_write_data(png_ptr, buf, (png_size_t)4);
+}
+
+/* Simple function to write the signature. If we have already written
+ * the magic bytes of the signature, or more likely, the PNG stream is
+ * being embedded into another stream and doesn't need its own signature,
+ * we should call png_set_sig_bytes() to tell libpng how many of the
+ * bytes have already been written.
+ */
+void
+png_write_sig(png_structp png_ptr)
+{
+ /* write the rest of the 8 byte signature */
+ png_write_data(png_ptr, &png_sig[png_ptr->sig_bytes],
+ (png_size_t)8 - png_ptr->sig_bytes);
+}
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ * information. Note that the rest of this code depends upon this
+ * information being correct.
+ */
+void
+png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
+ int bit_depth, int color_type, int compression_type, int filter_type,
+ int interlace_type)
+{
+ png_byte buf[13]; /* buffer to store the IHDR info */
+
+ png_debug(1, "in png_write_IHDR\n");
+ /* Check that we have valid input data from the application info */
+ switch (color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16: png_ptr->channels = 1; break;
+ default: png_error(png_ptr,"Invalid bit depth for grayscale image");
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGB image");
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8: png_ptr->channels = 1; break;
+ default: png_error(png_ptr, "Invalid bit depth for paletted image");
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGBA image");
+ png_ptr->channels = 4;
+ break;
+ default:
+ png_error(png_ptr, "Invalid image color type specified");
+ }
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid compression type specified");
+ compression_type = PNG_COMPRESSION_TYPE_BASE;
+ }
+
+ if (filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid filter type specified");
+ filter_type = PNG_FILTER_TYPE_BASE;
+ }
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ if (interlace_type != PNG_INTERLACE_NONE &&
+ interlace_type != PNG_INTERLACE_ADAM7)
+ {
+ png_warning(png_ptr, "Invalid interlace type specified");
+ interlace_type = PNG_INTERLACE_ADAM7;
+ }
+#else
+ interlace_type=PNG_INTERLACE_NONE;
+#endif
+
+ /* save off the relevent information */
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->color_type = (png_byte)color_type;
+ png_ptr->interlaced = (png_byte)interlace_type;
+ png_ptr->width = width;
+ png_ptr->height = height;
+
+ png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
+ png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
+ /* set the usr info, so any transformations can modify it */
+ png_ptr->usr_width = png_ptr->width;
+ png_ptr->usr_bit_depth = png_ptr->bit_depth;
+ png_ptr->usr_channels = png_ptr->channels;
+
+ /* pack the header information into the buffer */
+ png_save_uint_32(buf, width);
+ png_save_uint_32(buf + 4, height);
+ buf[8] = (png_byte)bit_depth;
+ buf[9] = (png_byte)color_type;
+ buf[10] = (png_byte)compression_type;
+ buf[11] = (png_byte)filter_type;
+ buf[12] = (png_byte)interlace_type;
+
+ /* write the chunk */
+ png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
+
+ /* initialize zlib with PNG info */
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+ if (!(png_ptr->do_filter))
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+ png_ptr->bit_depth < 8)
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ else
+ png_ptr->do_filter = PNG_ALL_FILTERS;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
+ {
+ if (png_ptr->do_filter != PNG_FILTER_NONE)
+ png_ptr->zlib_strategy = Z_FILTERED;
+ else
+ png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
+ png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
+ png_ptr->zlib_mem_level = 8;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
+ png_ptr->zlib_window_bits = 15;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
+ png_ptr->zlib_method = 8;
+ deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
+ png_ptr->zlib_method, png_ptr->zlib_window_bits,
+ png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_ptr->mode = PNG_HAVE_IHDR;
+}
+
+/* write the palette. We are careful not to trust png_color to be in the
+ * correct order for PNG, so people can redefine it to any convenient
+ * structure.
+ */
+void
+png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
+{
+ png_uint_32 i;
+ png_colorp pal_ptr;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_PLTE\n");
+ if (num_pal == 0 || num_pal > 256)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_error(png_ptr, "Invalid number of colors in palette");
+ }
+ else
+ {
+ png_warning(png_ptr, "Invalid number of colors in palette");
+ return;
+ }
+ }
+
+ png_ptr->num_palette = (png_uint_16)num_pal;
+ png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
+
+ png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3);
+ for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
+ {
+ buf[0] = pal_ptr->red;
+ buf[1] = pal_ptr->green;
+ buf[2] = pal_ptr->blue;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ }
+ png_write_chunk_end(png_ptr);
+ png_ptr->mode |= PNG_HAVE_PLTE;
+}
+
+/* write an IDAT chunk */
+void
+png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_debug(1, "in png_write_IDAT\n");
+ png_write_chunk(png_ptr, png_IDAT, data, length);
+ png_ptr->mode |= PNG_HAVE_IDAT;
+}
+
+/* write an IEND chunk */
+void
+png_write_IEND(png_structp png_ptr)
+{
+ png_debug(1, "in png_write_IEND\n");
+ png_write_chunk(png_ptr, png_IEND, NULL, (png_size_t)0);
+ png_ptr->mode |= PNG_HAVE_IEND;
+}
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+/* write a gAMA chunk */
+void
+png_write_gAMA(png_structp png_ptr, double file_gamma)
+{
+ png_uint_32 igamma;
+ png_byte buf[4];
+
+ png_debug(1, "in png_write_gAMA\n");
+ /* file_gamma is saved in 1/1000000ths */
+ igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
+ png_save_uint_32(buf, igamma);
+ png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
+}
+#endif
+
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+/* write a sRGB chunk */
+void
+png_write_sRGB(png_structp png_ptr, int srgb_intent)
+{
+ png_byte buf[1];
+
+ png_debug(1, "in png_write_sRGB\n");
+ if(srgb_intent >= PNG_sRGB_INTENT_LAST)
+ png_warning(png_ptr,
+ "Invalid sRGB rendering intent specified");
+ buf[0]=(png_byte)srgb_intent;
+ png_write_chunk(png_ptr, png_sRGB, buf, (png_size_t)1);
+}
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+/* write the sBIT chunk */
+void
+png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
+{
+ png_byte buf[4];
+ png_size_t size;
+
+ png_debug(1, "in png_write_sBIT\n");
+ /* make sure we don't depend upon the order of PNG_COLOR_8 */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_byte maxbits;
+
+ maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8 : png_ptr->usr_bit_depth;
+ if (sbit->red == 0 || sbit->red > maxbits ||
+ sbit->green == 0 || sbit->green > maxbits ||
+ sbit->blue == 0 || sbit->blue > maxbits)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->red;
+ buf[1] = sbit->green;
+ buf[2] = sbit->blue;
+ size = 3;
+ }
+ else
+ {
+ if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->gray;
+ size = 1;
+ }
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[size++] = sbit->alpha;
+ }
+
+ png_write_chunk(png_ptr, png_sBIT, buf, size);
+}
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+/* write the cHRM chunk */
+void
+png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y)
+{
+ png_uint_32 itemp;
+ png_byte buf[32];
+
+ png_debug(1, "in png_write_cHRM\n");
+ /* each value is saved int 1/1000000ths */
+ if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
+ white_x + white_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point specified");
+ return;
+ }
+ itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
+ png_save_uint_32(buf, itemp);
+ itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 4, itemp);
+
+ if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
+ red_x + red_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point specified");
+ return;
+ }
+ itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 8, itemp);
+ itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 12, itemp);
+
+ if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
+ green_x + green_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point specified");
+ return;
+ }
+ itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 16, itemp);
+ itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 20, itemp);
+
+ if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
+ blue_x + blue_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point specified");
+ return;
+ }
+ itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 24, itemp);
+ itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 28, itemp);
+
+ png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32);
+}
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+/* write the tRNS chunk */
+void
+png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
+ int num_trans, int color_type)
+{
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_tRNS\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
+ {
+ png_warning(png_ptr,"Invalid number of transparent colors specified");
+ return;
+ }
+ /* write the chunk out as it is */
+ png_write_chunk(png_ptr, png_tRNS, trans, (png_size_t)num_trans);
+ }
+ else if (color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ /* one 16 bit value */
+ png_save_uint_16(buf, tran->gray);
+ png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);
+ }
+ else if (color_type == PNG_COLOR_TYPE_RGB)
+ {
+ /* three 16 bit values */
+ png_save_uint_16(buf, tran->red);
+ png_save_uint_16(buf + 2, tran->green);
+ png_save_uint_16(buf + 4, tran->blue);
+ png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);
+ }
+ else
+ {
+ png_warning(png_ptr, "Can't write tRNS with an alpha channel");
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+/* write the background chunk */
+void
+png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
+{
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_bKGD\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (back->index > png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Invalid background palette index");
+ return;
+ }
+ buf[0] = back->index;
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
+ }
+ else if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_save_uint_16(buf, back->red);
+ png_save_uint_16(buf + 2, back->green);
+ png_save_uint_16(buf + 4, back->blue);
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
+ }
+ else
+ {
+ png_save_uint_16(buf, back->gray);
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+/* write the histogram */
+void
+png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
+{
+ int i;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_hIST\n");
+ if (num_hist > (int)png_ptr->num_palette)
+ {
+ png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
+ png_ptr->num_palette);
+ png_warning(png_ptr, "Invalid number of histogram entries specified");
+ return;
+ }
+
+ png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));
+ for (i = 0; i < num_hist; i++)
+ {
+ png_save_uint_16(buf, hist[i]);
+ png_write_chunk_data(png_ptr, buf, (png_size_t)2);
+ }
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) || \
+ defined(PNG_WRITE_pCAL_SUPPORTED)
+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
+ * and if invalid, correct the keyword rather than discarding the entire
+ * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
+ * length, forbids leading or trailing whitespace, multiple internal spaces,
+ * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
+ *
+ * The new_key is allocated to hold the corrected keyword and must be freed
+ * by the calling routine. This avoids problems with trying to write to
+ * static keywords without having to have duplicate copies of the strings.
+ */
+png_size_t
+png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
+{
+ png_size_t key_len;
+ png_charp kp, dp;
+ int kflag;
+
+ png_debug(1, "in png_check_keyword\n");
+ *new_key = NULL;
+
+ if (key == NULL || (key_len = png_strlen(key)) == 0)
+ {
+ png_chunk_warning(png_ptr, "zero length keyword");
+ return ((png_size_t)0);
+ }
+
+ png_debug1(2, "Keyword to be checked is '%s'\n", key);
+
+ *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 1));
+
+ /* Replace non-printing characters with a blank and print a warning */
+ for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
+ {
+ if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
+ {
+#if !defined(PNG_NO_STDIO)
+ char msg[40];
+
+ sprintf(msg, "invalid keyword character 0x%02X", *kp);
+ png_chunk_warning(png_ptr, msg);
+#else
+ png_chunk_warning(png_ptr, "invalid character in keyword");
+#endif
+ *dp = ' ';
+ }
+ else
+ {
+ *dp = *kp;
+ }
+ }
+ *dp = '\0';
+
+ /* Remove any trailing white space. */
+ kp = *new_key + key_len - 1;
+ if (*kp == ' ')
+ {
+ png_chunk_warning(png_ptr, "trailing spaces removed from keyword");
+
+ while (*kp == ' ')
+ {
+ *(kp--) = '\0';
+ key_len--;
+ }
+ }
+
+ /* Remove any leading white space. */
+ kp = *new_key;
+ if (*kp == ' ')
+ {
+ png_chunk_warning(png_ptr, "leading spaces removed from keyword");
+
+ while (*kp == ' ')
+ {
+ kp++;
+ key_len--;
+ }
+ }
+
+ png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
+
+ /* Remove multiple internal spaces. */
+ for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
+ {
+ if (*kp == ' ' && kflag == 0)
+ {
+ *(dp++) = *kp;
+ kflag = 1;
+ }
+ else if (*kp == ' ')
+ {
+ key_len--;
+ }
+ else
+ {
+ *(dp++) = *kp;
+ kflag = 0;
+ }
+ }
+ *dp = '\0';
+
+ if (key_len == 0)
+ {
+ png_chunk_warning(png_ptr, "zero length keyword");
+ }
+
+ if (key_len > 79)
+ {
+ png_chunk_warning(png_ptr, "keyword length must be 1 - 79 characters");
+ new_key[79] = '\0';
+ key_len = 79;
+ }
+
+ return (key_len);
+}
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+/* write a tEXt chunk */
+void
+png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len)
+{
+ png_size_t key_len;
+ png_charp new_key;
+
+ png_debug(1, "in png_write_tEXt\n");
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in tEXt chunk");
+ return;
+ }
+
+ if (text == NULL || *text == '\0')
+ text_len = 0;
+
+ /* make sure we include the 0 after the key */
+ png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)key_len+text_len+1);
+ png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
+ if (text_len)
+ png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_key);
+}
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+/* write a compressed text chunk */
+void
+png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len, int compression)
+{
+ png_size_t key_len;
+ char buf[1];
+ png_charp new_key;
+ int i, ret;
+ png_charpp output_ptr = NULL; /* array of pointers to output */
+ int num_output_ptr = 0; /* number of output pointers used */
+ int max_output_ptr = 0; /* size of output_ptr */
+
+ png_debug(1, "in png_write_zTXt\n");
+
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in zTXt chunk");
+ return;
+ }
+
+ if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
+ {
+ png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
+ png_free(png_ptr, new_key);
+ return;
+ }
+
+ png_free(png_ptr, new_key);
+
+ if (compression >= PNG_TEXT_COMPRESSION_LAST)
+ {
+#if !defined(PNG_NO_STDIO)
+ char msg[50];
+ sprintf(msg, "Unknown zTXt compression type %d", compression);
+ png_warning(png_ptr, msg);
+#else
+ png_warning(png_ptr, "Unknown zTXt compression type");
+#endif
+ compression = PNG_TEXT_COMPRESSION_zTXt;
+ }
+
+ /* We can't write the chunk until we find out how much data we have,
+ * which means we need to run the compressor first and save the
+ * output. This shouldn't be a problem, as the vast majority of
+ * comments should be reasonable, but we will set up an array of
+ * malloc'd pointers to be sure.
+ *
+ * If we knew the application was well behaved, we could simplify this
+ * greatly by assuming we can always malloc an output buffer large
+ * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
+ * and malloc this directly. The only time this would be a bad idea is
+ * if we can't malloc more than 64K and we have 64K of random input
+ * data, or if the input string is incredibly large (although this
+ * wouldn't cause a failure, just a slowdown due to swapping).
+ */
+
+ /* set up the compression buffers */
+ png_ptr->zstream.avail_in = (uInt)text_len;
+ png_ptr->zstream.next_in = (Bytef *)text;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
+
+ /* this is the same compression loop as in png_write_row() */
+ do
+ {
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ if (ret != Z_OK)
+ {
+ /* error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ /* check to see if we need more room */
+ if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
+ {
+ /* make sure the output array has room */
+ if (num_output_ptr >= max_output_ptr)
+ {
+ int old_max;
+
+ old_max = max_output_ptr;
+ max_output_ptr = num_output_ptr + 4;
+ if (output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = output_ptr;
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(max_output_ptr * sizeof (png_charpp)));
+ png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(max_output_ptr * sizeof (png_charp)));
+ }
+
+ /* save the data */
+ output_ptr[num_output_ptr] = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ num_output_ptr++;
+
+ /* and reset the buffer */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ /* continue until we don't have any more to compress */
+ } while (png_ptr->zstream.avail_in);
+
+ /* finish the compression */
+ do
+ {
+ /* tell zlib we are finished */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ /* we got an error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
+ {
+ /* check to make sure our output array has room */
+ if (num_output_ptr >= max_output_ptr)
+ {
+ int old_max;
+
+ old_max = max_output_ptr;
+ max_output_ptr = num_output_ptr + 4;
+ if (output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = output_ptr;
+ /* This could be optimized to realloc() */
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(max_output_ptr * sizeof (png_charpp)));
+ png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(max_output_ptr * sizeof (png_charp)));
+ }
+
+ /* save off the data */
+ output_ptr[num_output_ptr] = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ num_output_ptr++;
+
+ /* and reset the buffer pointers */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* text length is number of buffers plus last buffer */
+ text_len = png_ptr->zbuf_size * num_output_ptr;
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
+
+ /* write start of chunk */
+ png_write_chunk_start(png_ptr, png_zTXt, (png_uint_32)(key_len+text_len+2));
+ /* write key */
+ png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
+ buf[0] = (png_byte)compression;
+ /* write compression */
+ png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
+
+ /* write saved output buffers, if any */
+ for (i = 0; i < num_output_ptr; i++)
+ {
+ png_write_chunk_data(png_ptr,(png_bytep)output_ptr[i],png_ptr->zbuf_size);
+ png_free(png_ptr, output_ptr[i]);
+ }
+ if (max_output_ptr != 0)
+ png_free(png_ptr, output_ptr);
+ /* write anything left in zbuf */
+ if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
+ png_write_chunk_data(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ /* close the chunk */
+ png_write_chunk_end(png_ptr);
+
+ /* reset zlib for another zTXt or the image data */
+ deflateReset(&png_ptr->zstream);
+}
+#endif
+
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+/* write the oFFs chunk */
+void
+png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
+ png_uint_32 y_offset,
+ int unit_type)
+{
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_oFFs\n");
+ if (unit_type >= PNG_OFFSET_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
+
+ png_save_uint_32(buf, x_offset);
+ png_save_uint_32(buf + 4, y_offset);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* write the pCAL chunk (png-scivis-19970203) */
+void
+png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
+ png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
+{
+ png_size_t purpose_len, units_len, total_len;
+ png_uint_32p params_len;
+ png_byte buf[10];
+ png_charp new_purpose;
+ int i;
+
+ png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
+ if (type >= PNG_EQUATION_LAST)
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+
+ purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
+ png_debug1(3, "pCAL purpose length = %d\n", purpose_len);
+ units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
+ png_debug1(3, "pCAL units length = %d\n", units_len);
+ total_len = purpose_len + units_len + 10;
+
+ params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
+ *sizeof(png_uint_32)));
+
+ /* Find the length of each parameter, making sure we don't count the
+ null terminator for the last parameter. */
+ for (i = 0; i < nparams; i++)
+ {
+ params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
+ png_debug2(3, "pCAL parameter %d length = %d\n", i, params_len[i]);
+ total_len += (png_size_t)params_len[i];
+ }
+
+ png_debug1(3, "pCAL total length = %d\n", total_len);
+ png_write_chunk_start(png_ptr, png_pCAL, (png_uint_32)total_len);
+ png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
+ png_save_int_32(buf, X0);
+ png_save_int_32(buf + 4, X1);
+ buf[8] = (png_byte)type;
+ buf[9] = (png_byte)nparams;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)10);
+ png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
+
+ png_free(png_ptr, new_purpose);
+
+ for (i = 0; i < nparams; i++)
+ {
+ png_write_chunk_data(png_ptr, (png_bytep)params[i],
+ (png_size_t)params_len[i]);
+ }
+
+ png_free(png_ptr, params_len);
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+/* write the pHYs chunk */
+void
+png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
+ png_uint_32 y_pixels_per_unit,
+ int unit_type)
+{
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_pHYs\n");
+ if (unit_type >= PNG_RESOLUTION_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
+
+ png_save_uint_32(buf, x_pixels_per_unit);
+ png_save_uint_32(buf + 4, y_pixels_per_unit);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* Write the tIME chunk. Use either png_convert_from_struct_tm()
+ * or png_convert_from_time_t(), or fill in the structure yourself.
+ */
+void
+png_write_tIME(png_structp png_ptr, png_timep mod_time)
+{
+ png_byte buf[7];
+
+ png_debug(1, "in png_write_tIME\n");
+ if (mod_time->month > 12 || mod_time->month < 1 ||
+ mod_time->day > 31 || mod_time->day < 1 ||
+ mod_time->hour > 23 || mod_time->second > 60)
+ {
+ png_warning(png_ptr, "Invalid time specified for tIME chunk");
+ return;
+ }
+
+ png_save_uint_16(buf, mod_time->year);
+ buf[2] = mod_time->month;
+ buf[3] = mod_time->day;
+ buf[4] = mod_time->hour;
+ buf[5] = mod_time->minute;
+ buf[6] = mod_time->second;
+
+ png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
+}
+#endif
+
+/* initializes the row writing capability of libpng */
+void
+png_write_start_row(png_structp png_ptr)
+{
+ png_size_t buf_size;
+
+ png_debug(1, "in png_write_start_row\n");
+ buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels *
+ png_ptr->usr_bit_depth + 7) >> 3) + 1);
+
+ /* set up row buffer */
+ png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+ png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
+
+ /* set up filtering buffer, if using this filter */
+ if (png_ptr->do_filter & PNG_FILTER_SUB)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ /* We only need to keep the previous row if we are using one of these. */
+ if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
+ {
+ /* set up previous row buffer */
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+ png_memset(png_ptr->prev_row, 0, buf_size);
+
+ if (png_ptr->do_filter & PNG_FILTER_UP)
+ {
+ png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_AVG)
+ {
+ png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_PAETH)
+ {
+ png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+ }
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* if interlaced, we need to set up width and height of pass */
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
+ png_pass_start[0]) / png_pass_inc[0];
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ }
+ else
+#endif
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+}
+
+/* Internal use only. Called when finished processing a row of data. */
+void
+png_write_finish_row(png_structp png_ptr)
+{
+ int ret;
+
+ png_debug(1, "in png_write_finish_row\n");
+ /* next row */
+ png_ptr->row_number++;
+
+ /* see if we are done */
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* if interlaced, go to next pass */
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ if (png_ptr->transformations & PNG_INTERLACE)
+ {
+ png_ptr->pass++;
+ }
+ else
+ {
+ /* loop until we find a non-zero width or height pass */
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->usr_width = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+ } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
+
+ }
+
+ /* reset the row above the image for the next pass */
+ if (png_ptr->pass < 7)
+ {
+ if (png_ptr->prev_row != NULL)
+ png_memset(png_ptr->prev_row, 0,
+ (png_size_t) (((png_uint_32)png_ptr->usr_channels *
+ (png_uint_32)png_ptr->usr_bit_depth *
+ png_ptr->width + 7) >> 3) + 1);
+ return;
+ }
+ }
+#endif
+
+ /* if we get here, we've just written the last row, so we need
+ to flush the compressor */
+ do
+ {
+ /* tell the compressor we are done */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+ /* check for an error */
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* write any extra space */
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out);
+ }
+
+ deflateReset(&png_ptr->zstream);
+}
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Pick out the correct pixels for the interlace pass.
+ * The basic idea here is to go through the row with a source
+ * pointer and a destination pointer (sp and dp), and copy the
+ * correct pixels for the pass. As the row gets compacted,
+ * sp will always be >= dp, so we should never overwrite anything.
+ * See the default: case for the easiest code to understand.
+ */
+void
+png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
+{
+ png_debug(1, "in png_do_write_interlace\n");
+ /* we don't have to do anything on the last pass (6) */
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && pass < 6)
+#else
+ if (pass < 6)
+#endif
+ {
+ /* each pixel depth is handled separately */
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ d = 0;
+ shift = 7;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 3);
+ value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 7;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift--;
+
+ }
+ if (shift != 7)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ shift = 6;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 2);
+ value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 2;
+ }
+ if (shift != 6)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ shift = 4;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 1);
+ value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 4;
+ }
+ if (shift != 4)
+ *dp = (png_byte)d;
+ break;
+ }
+ default:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ png_size_t pixel_bytes;
+
+ /* start at the beginning */
+ dp = row;
+ /* find out how many bytes each pixel takes up */
+ pixel_bytes = (row_info->pixel_depth >> 3);
+ /* loop through the row, only looking at the pixels that
+ matter */
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ /* find out where the original pixel is */
+ sp = row + (png_size_t)i * pixel_bytes;
+ /* move the pixel */
+ if (dp != sp)
+ png_memcpy(dp, sp, pixel_bytes);
+ /* next pixel */
+ dp += pixel_bytes;
+ }
+ break;
+ }
+ }
+ /* set new row width */
+ row_info->width = (row_info->width +
+ png_pass_inc[pass] - 1 -
+ png_pass_start[pass]) /
+ png_pass_inc[pass];
+ row_info->rowbytes = ((row_info->width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+/* This filters the row, chooses which filter to use, if it has not already
+ * been specified by the application, and then writes the row out with the
+ * chosen filter.
+ */
+#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
+#define PNG_HISHIFT 10
+#define PNG_LOMASK ((png_uint_32)0xffffL)
+#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
+void
+png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
+{
+ png_bytep prev_row, best_row, row_buf;
+ png_uint_32 mins, bpp;
+ png_byte filter_to_do = png_ptr->do_filter;
+ png_uint_32 row_bytes = row_info->rowbytes;
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ int num_p_filters = (int)png_ptr->num_prev_filters;
+#endif
+
+ png_debug(1, "in png_write_find_filter\n");
+ /* find out how many bytes offset each pixel is */
+ bpp = (row_info->pixel_depth + 7) / 8;
+
+ prev_row = png_ptr->prev_row;
+ best_row = row_buf = png_ptr->row_buf;
+ mins = PNG_MAXSUM;
+
+ /* The prediction method we use is to find which method provides the
+ * smallest value when summing the absolute values of the distances
+ * from zero, using anything >= 128 as negative numbers. This is known
+ * as the "minimum sum of absolute differences" heuristic. Other
+ * heuristics are the "weighted minimum sum of absolute differences"
+ * (experimental and can in theory improve compression), and the "zlib
+ * predictive" method (not implemented yet), which does test compressions
+ * of lines using different filter methods, and then chooses the
+ * (series of) filter(s) that give minimum compressed data size (VERY
+ * computationally expensive).
+ *
+ * GRR 980525: consider also
+ * (1) minimum sum of absolute differences from running average (i.e.,
+ * keep running sum of non-absolute differences & count of bytes)
+ * [track dispersion, too? restart average if dispersion too large?]
+ * (1b) minimum sum of absolute differences from sliding average, probably
+ * with window size <= deflate window (usually 32K)
+ * (2) minimum sum of squared differences from zero or running average
+ * (i.e., ~ root-mean-square approach)
+ */
+
+
+ /* We don't need to test the 'no filter' case if this is the only filter
+ * that has been chosen, as it doesn't actually do anything to the data.
+ */
+ if (filter_to_do & PNG_FILTER_NONE &&
+ filter_to_do != PNG_FILTER_NONE)
+ {
+ png_bytep rp;
+ png_uint_32 sum = 0;
+ png_uint_32 i;
+ int v;
+
+ for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
+ {
+ v = *rp;
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ int j;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
+
+ /* Reduce the sum if we match any of the previous rows */
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ /* Factor in the cost of this filter (this is here for completeness,
+ * but it makes no sense to have a "cost" for the NONE filter, as
+ * it has the minimum possible computational cost - none).
+ */
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+ mins = sum;
+ }
+
+ /* sub filter */
+ if (filter_to_do == PNG_FILTER_SUB)
+ /* it's the only filter so no testing is needed */
+ {
+ png_bytep rp, lp, dp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ *dp = *rp;
+ }
+ for (lp = row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+ }
+ best_row = png_ptr->sub_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_SUB)
+ {
+ png_bytep rp, dp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* We temporarily increase the "minimum sum" by the factor we
+ * would reduce the sum of this filter, so that we can do the
+ * early exit comparison without scaling the sum each time.
+ */
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ v = *dp = *rp;
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_info->rowbytes;
+ i++, rp++, lp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
+ {
+ sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->sub_row;
+ }
+ }
+
+ /* up filter */
+ if (filter_to_do == PNG_FILTER_UP)
+ {
+ png_bytep rp, dp, pp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
+ pp = prev_row + 1; i < row_bytes;
+ i++, rp++, pp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+ }
+ best_row = png_ptr->up_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_UP)
+ {
+ png_bytep rp, dp, pp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
+ pp = prev_row + 1; i < row_bytes; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->up_row;
+ }
+ }
+
+ /* avg filter */
+ if (filter_to_do == PNG_FILTER_AVG)
+ {
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+ }
+ for (lp = row_buf + 1; i < row_bytes; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+ & 0xff);
+ }
+ best_row = png_ptr->avg_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_AVG)
+ {
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_bytes; i++)
+ {
+ v = *dp++ =
+ (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->avg_row;
+ }
+ }
+
+ /* Paeth filter */
+ if (filter_to_do == PNG_FILTER_PAETH)
+ {
+ png_bytep rp, dp, pp, cp, lp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+ }
+
+ for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+ }
+ best_row = png_ptr->paeth_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_PAETH)
+ {
+ png_bytep rp, dp, pp, cp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+ for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+#ifndef PNG_SLOW_PAETH
+ p = b - c;
+ pc = a - c;
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+#else /* PNG_SLOW_PAETH */
+ p = a + b - c;
+ pa = abs(p - a);
+ pb = abs(p - b);
+ pc = abs(p - c);
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+#endif /* PNG_SLOW_PAETH */
+
+ v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ best_row = png_ptr->paeth_row;
+ }
+ }
+
+ /* Do the actual writing of the filtered row data from the chosen filter. */
+
+ png_write_filtered_row(png_ptr, best_row);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* Save the type of filter we picked this time for future calculations */
+ if (png_ptr->num_prev_filters > 0)
+ {
+ int j;
+ for (j = 1; j < num_p_filters; j++)
+ {
+ png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
+ }
+ png_ptr->prev_filters[j] = best_row[0];
+ }
+#endif
+}
+
+
+/* Do the actual writing of a previously filtered row. */
+void
+png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
+{
+ png_debug(1, "in png_write_filtered_row\n");
+ png_debug1(2, "filter = %d\n", filtered_row[0]);
+ /* set up the zlib input buffer */
+ png_ptr->zstream.next_in = filtered_row;
+ png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
+ /* repeat until we have compressed all the data */
+ do
+ {
+ int ret; /* return of zlib */
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ /* see if it is time to write another IDAT */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ /* repeat until all data has been compressed */
+ } while (png_ptr->zstream.avail_in);
+
+ /* swap the current and previous rows */
+ if (png_ptr->prev_row != NULL)
+ {
+ png_bytep tptr;
+
+ tptr = png_ptr->prev_row;
+ png_ptr->prev_row = png_ptr->row_buf;
+ png_ptr->row_buf = tptr;
+ }
+
+ /* finish row - updates counters and flushes zlib if last row */
+ png_write_finish_row(png_ptr);
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->flush_rows++;
+
+ if (png_ptr->flush_dist > 0 &&
+ png_ptr->flush_rows >= png_ptr->flush_dist)
+ {
+ png_write_flush(png_ptr);
+ }
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+}