summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Schalnat <schalnat at group42.com>1995-07-20 02:43:20 -0500
committerGlenn Randers-Pehrson <glennrp at users.sourceforge.net>2009-04-06 16:04:01 -0500
commit0d5805822f8817a17937462a2fd0606ffdad378e (patch)
tree2baf3b5f79b7582b7f5936fd1b232facc2f29b01
downloadlibpng-0d5805822f8817a17937462a2fd0606ffdad378e.tar.gz
Imported from libpng-0.71.tarv0.71
-rw-r--r--ansi2knr.c488
-rw-r--r--example.c360
-rw-r--r--libpng.txt821
-rw-r--r--makefile49
-rw-r--r--makefile.knr61
-rw-r--r--makefile.mip50
-rw-r--r--makefile.std49
-rw-r--r--png.c172
-rw-r--r--png.h913
-rw-r--r--pngchang.txt44
-rw-r--r--pngrcb.c212
-rw-r--r--pngread.c642
-rw-r--r--pngrtran.c2774
-rw-r--r--pngrutil.c1243
-rw-r--r--pngstub.c387
-rw-r--r--pngtest.c180
-rw-r--r--pngtest.pngbin0 -> 7261 bytes
-rw-r--r--pngtodo.txt22
-rw-r--r--pngtrans.c192
-rw-r--r--pngwrite.c408
-rw-r--r--pngwtran.c331
-rw-r--r--pngwutil.c1080
-rw-r--r--readme.txt79
23 files changed, 10557 insertions, 0 deletions
diff --git a/ansi2knr.c b/ansi2knr.c
new file mode 100644
index 000000000..392421543
--- /dev/null
+++ b/ansi2knr.c
@@ -0,0 +1,488 @@
+/* Copyright (C) 1989, 1991, 1993 Aladdin Enterprises. All rights reserved. */
+
+/* ansi2knr.c */
+/* Convert ANSI function declarations to K&R syntax */
+
+/*
+ansi2knr is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+to anyone for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing. Refer
+to the GNU General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+ansi2knr, but only under the conditions described in the GNU
+General Public License. A copy of this license is supposed to have been
+given to you along with ansi2knr so you can know your rights and
+responsibilities. It should be in a file named COPYING. Among other
+things, the copyright notice and this notice must be preserved on all
+copies.
+*/
+
+/*
+---------- Here is the GNU GPL file COPYING, referred to above ----------
+----- These terms do NOT apply to the JPEG software itself; see README ------
+
+ GHOSTSCRIPT GENERAL PUBLIC LICENSE
+ (Clarified 11 Feb 1988)
+
+ Copyright (C) 1988 Richard M. Stallman
+ Everyone is permitted to copy and distribute verbatim copies of this
+ license, but changing it is not allowed. You can also use this wording
+ to make the terms for other programs.
+
+ The license agreements of most software companies keep you at the
+mercy of those companies. By contrast, our general public license is
+intended to give everyone the right to share Ghostscript. To make sure
+that you get the rights we want you to have, we need to make
+restrictions that forbid anyone to deny you these rights or to ask you
+to surrender the rights. Hence this license agreement.
+
+ Specifically, we want to make sure that you have the right to give
+away copies of Ghostscript, that you receive source code or else can get
+it if you want it, that you can change Ghostscript or use pieces of it
+in new free programs, and that you know you can do these things.
+
+ To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights. For example, if you distribute
+copies of Ghostscript, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must tell them their rights.
+
+ Also, for our own protection, we must make certain that everyone finds
+out that there is no warranty for Ghostscript. If Ghostscript is
+modified by someone else and passed on, we want its recipients to know
+that what they have is not what we distributed, so that any problems
+introduced by others will not reflect on our reputation.
+
+ Therefore we (Richard M. Stallman and the Free Software Foundation,
+Inc.) make the following terms which say what you must do to be allowed
+to distribute or change Ghostscript.
+
+
+ COPYING POLICIES
+
+ 1. You may copy and distribute verbatim copies of Ghostscript source
+code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy a valid copyright and license
+notice "Copyright (C) 1989 Aladdin Enterprises. All rights reserved.
+Distributed by Free Software Foundation, Inc." (or with whatever year is
+appropriate); keep intact the notices on all files that refer to this
+License Agreement and to the absence of any warranty; and give any other
+recipients of the Ghostscript program a copy of this License Agreement
+along with the program. You may charge a distribution fee for the
+physical act of transferring a copy.
+
+ 2. You may modify your copy or copies of Ghostscript or any portion of
+it, and copy and distribute such modifications under the terms of
+Paragraph 1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish,
+ that in whole or in part contains or is a derivative of Ghostscript
+ or any part thereof, to be licensed at no charge to all third
+ parties on terms identical to those contained in this License
+ Agreement (except that you may choose to grant more extensive
+ warranty protection to some or all third parties, at your option).
+
+ c) You may charge a distribution fee for the physical act of
+ transferring a copy, and you may at your option offer warranty
+ protection in exchange for a fee.
+
+Mere aggregation of another unrelated program with this program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other program under the scope of these terms.
+
+ 3. You may copy and distribute Ghostscript (or a portion or derivative
+of it, under Paragraph 2) in object code or executable form under the
+terms of Paragraphs 1 and 2 above provided that you also do one of the
+following:
+
+ a) accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal
+ shipping charge) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+For an executable file, complete source code means all the source code for
+all modules it contains; but, as a special exception, it need not include
+source code for modules which are standard libraries that accompany the
+operating system on which the executable file runs.
+
+ 4. You may not copy, sublicense, distribute or transfer Ghostscript
+except as expressly provided under this License Agreement. Any attempt
+otherwise to copy, sublicense, distribute or transfer Ghostscript is
+void and your rights to use the program under this License agreement
+shall be automatically terminated. However, parties who have received
+computer software programs from you with this License Agreement will not
+have their licenses terminated so long as such parties remain in full
+compliance.
+
+ 5. If you wish to incorporate parts of Ghostscript into other free
+programs whose distribution conditions are different, write to the Free
+Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not
+yet worked out a simple rule that can be stated here, but we will often
+permit this. We will be guided by the two goals of preserving the free
+status of all derivatives of our free software and of promoting the
+sharing and reuse of software.
+
+Your comments and suggestions about our licensing policies and our
+software are welcome! Please contact the Free Software Foundation,
+Inc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296.
+
+ NO WARRANTY
+
+ BECAUSE GHOSTSCRIPT IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
+WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD
+M. STALLMAN, ALADDIN ENTERPRISES, L. PETER DEUTSCH, AND/OR OTHER PARTIES
+PROVIDE GHOSTSCRIPT "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF GHOSTSCRIPT IS WITH
+YOU. SHOULD GHOSTSCRIPT PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., L. PETER DEUTSCH, ALADDIN
+ENTERPRISES, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE
+GHOSTSCRIPT AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING
+ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GHOSTSCRIPT, EVEN IF YOU
+HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM
+BY ANY OTHER PARTY.
+
+-------------------- End of file COPYING ------------------------------
+*/
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef BSD
+#include <strings.h>
+#else
+#ifdef VMS
+ extern int strlen(), strncmp();
+#else
+#include <string.h>
+#endif
+#endif
+
+/* malloc and free should be declared in stdlib.h, */
+/* but if you've got a K&R compiler, they probably aren't. */
+#ifdef MSDOS
+#include <malloc.h>
+#else
+#ifdef VMS
+ extern char *malloc();
+ extern void free();
+#else
+ extern char *malloc();
+ extern int free();
+#endif
+#endif
+
+/* Usage:
+ ansi2knr input_file [output_file]
+ * If no output_file is supplied, output goes to stdout.
+ * There are no error messages.
+ *
+ * ansi2knr recognizes functions by seeing a non-keyword identifier
+ * at the left margin, followed by a left parenthesis,
+ * with a right parenthesis as the last character on the line.
+ * It will recognize a multi-line header provided that the last character
+ * of the last line of the header is a right parenthesis,
+ * and no intervening line ends with a left brace or a semicolon.
+ * These algorithms ignore whitespace and comments, except that
+ * the function name must be the first thing on the line.
+ * The following constructs will confuse it:
+ * - Any other construct that starts at the left margin and
+ * follows the above syntax (such as a macro or function call).
+ * - Macros that tinker with the syntax of the function header.
+ */
+
+/* Scanning macros */
+#define isidchar(ch) (isalnum(ch) || (ch) == '_')
+#define isidfirstchar(ch) (isalpha(ch) || (ch) == '_')
+
+/* Forward references */
+char *skipspace();
+int writeblanks();
+int test1();
+int convert1();
+
+/* The main program */
+main(argc, argv)
+ int argc;
+ char *argv[];
+{ FILE *in, *out;
+#define bufsize 5000 /* arbitrary size */
+ char *buf;
+ char *line;
+ switch ( argc )
+ {
+ default:
+ printf("Usage: ansi2knr input_file [output_file]\n");
+ exit(0);
+ case 2:
+ out = stdout; break;
+ case 3:
+ out = fopen(argv[2], "w");
+ if ( out == NULL )
+ { fprintf(stderr, "Cannot open %s\n", argv[2]);
+ exit(1);
+ }
+ }
+ in = fopen(argv[1], "r");
+ if ( in == NULL )
+ { fprintf(stderr, "Cannot open %s\n", argv[1]);
+ exit(1);
+ }
+ fprintf(out, "#line 1 \"%s\"\n", argv[1]);
+ buf = malloc(bufsize);
+ line = buf;
+ while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
+ { switch ( test1(buf) )
+ {
+ case 1: /* a function */
+ convert1(buf, out);
+ break;
+ case -1: /* maybe the start of a function */
+ line = buf + strlen(buf);
+ if ( line != buf + (bufsize - 1) ) /* overflow check */
+ continue;
+ /* falls through */
+ default: /* not a function */
+ fputs(buf, out);
+ break;
+ }
+ line = buf;
+ }
+ if ( line != buf ) fputs(buf, out);
+ free(buf);
+ fclose(out);
+ fclose(in);
+ return 0;
+}
+
+/* Skip over space and comments, in either direction. */
+char *
+skipspace(p, dir)
+ register char *p;
+ register int dir; /* 1 for forward, -1 for backward */
+{ for ( ; ; )
+ { while ( isspace(*p) ) p += dir;
+ if ( !(*p == '/' && p[dir] == '*') ) break;
+ p += dir; p += dir;
+ while ( !(*p == '*' && p[dir] == '/') )
+ { if ( *p == 0 ) return p; /* multi-line comment?? */
+ p += dir;
+ }
+ p += dir; p += dir;
+ }
+ return p;
+}
+
+/*
+ * Write blanks over part of a string.
+ */
+int
+writeblanks(start, end)
+ char *start;
+ char *end;
+{ char *p;
+ for ( p = start; p < end; p++ ) *p = ' ';
+ return 0;
+}
+
+/*
+ * Test whether the string in buf is a function definition.
+ * The string may contain and/or end with a newline.
+ * Return as follows:
+ * 0 - definitely not a function definition;
+ * 1 - definitely a function definition;
+ * -1 - may be the beginning of a function definition,
+ * append another line and look again.
+ */
+int
+test1(buf)
+ char *buf;
+{ register char *p = buf;
+ char *bend;
+ char *endfn;
+ int contin;
+ if ( !isidfirstchar(*p) )
+ return 0; /* no name at left margin */
+ bend = skipspace(buf + strlen(buf) - 1, -1);
+ switch ( *bend )
+ {
+ case ')': contin = 1; break;
+ case '{':
+ case ';': return 0; /* not a function */
+ default: contin = -1;
+ }
+ while ( isidchar(*p) ) p++;
+ endfn = p;
+ p = skipspace(p, 1);
+ if ( *p++ != '(' )
+ return 0; /* not a function */
+ p = skipspace(p, 1);
+ if ( *p == ')' )
+ return 0; /* no parameters */
+ /* Check that the apparent function name isn't a keyword. */
+ /* We only need to check for keywords that could be followed */
+ /* by a left parenthesis (which, unfortunately, is most of them). */
+ { static char *words[] =
+ { "asm", "auto", "case", "char", "const", "double",
+ "extern", "float", "for", "if", "int", "long",
+ "register", "return", "short", "signed", "sizeof",
+ "static", "switch", "typedef", "unsigned",
+ "void", "volatile", "while", 0
+ };
+ char **key = words;
+ char *kp;
+ int len = endfn - buf;
+ while ( (kp = *key) != 0 )
+ { if ( strlen(kp) == len && !strncmp(kp, buf, len) )
+ return 0; /* name is a keyword */
+ key++;
+ }
+ }
+ return contin;
+}
+
+int
+convert1(buf, out)
+ char *buf;
+ FILE *out;
+{ char *endfn;
+ register char *p;
+ char **breaks;
+ unsigned num_breaks = 2; /* for testing */
+ char **btop;
+ char **bp;
+ char **ap;
+ /* Pre-ANSI implementations don't agree on whether strchr */
+ /* is called strchr or index, so we open-code it here. */
+ for ( endfn = buf; *(endfn++) != '('; ) ;
+top: p = endfn;
+ breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
+ if ( breaks == 0 )
+ { /* Couldn't allocate break table, give up */
+ fprintf(stderr, "Unable to allocate break table!\n");
+ fputs(buf, out);
+ return -1;
+ }
+ btop = breaks + num_breaks * 2 - 2;
+ bp = breaks;
+ /* Parse the argument list */
+ do
+ { int level = 0;
+ char *end = NULL;
+ if ( bp >= btop )
+ { /* Filled up break table. */
+ /* Allocate a bigger one and start over. */
+ free((char *)breaks);
+ num_breaks <<= 1;
+ goto top;
+ }
+ *bp++ = p;
+ /* Find the end of the argument */
+ for ( ; end == NULL; p++ )
+ { switch(*p)
+ {
+ case ',': if ( !level ) end = p; break;
+ case '(': level++; break;
+ case ')': if ( --level < 0 ) end = p; break;
+ case '/': p = skipspace(p, 1) - 1; break;
+ default: ;
+ }
+ }
+ p--; /* back up over terminator */
+ /* Find the name being declared. */
+ /* This is complicated because of procedure and */
+ /* array modifiers. */
+ for ( ; ; )
+ { p = skipspace(p - 1, -1);
+ switch ( *p )
+ {
+ case ']': /* skip array dimension(s) */
+ case ')': /* skip procedure args OR name */
+ { int level = 1;
+ while ( level )
+ switch ( *--p )
+ {
+ case ']': case ')': level++; break;
+ case '[': case '(': level--; break;
+ case '/': p = skipspace(p, -1) + 1; break;
+ default: ;
+ }
+ }
+ if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
+ { /* We found the name being declared */
+ while ( !isidfirstchar(*p) )
+ p = skipspace(p, 1) + 1;
+ goto found;
+ }
+ break;
+ default: goto found;
+ }
+ }
+found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
+ { p++;
+ if ( bp == breaks + 1 ) /* sole argument */
+ writeblanks(breaks[0], p);
+ else
+ writeblanks(bp[-1] - 1, p);
+ bp--;
+ }
+ else
+ { while ( isidchar(*p) ) p--;
+ *bp++ = p+1;
+ }
+ p = end;
+ }
+ while ( *p++ == ',' );
+ *bp = p;
+ /* Make a special check for 'void' arglist */
+ if ( bp == breaks+2 )
+ { p = skipspace(breaks[0], 1);
+ if ( !strncmp(p, "void", 4) )
+ { p = skipspace(p+4, 1);
+ if ( p == breaks[2] - 1 )
+ { bp = breaks; /* yup, pretend arglist is empty */
+ writeblanks(breaks[0], p + 1);
+ }
+ }
+ }
+ /* Put out the function name */
+ p = buf;
+ while ( p != endfn ) putc(*p, out), p++;
+ /* Put out the declaration */
+ for ( ap = breaks+1; ap < bp; ap += 2 )
+ { p = *ap;
+ while ( isidchar(*p) ) putc(*p, out), p++;
+ if ( ap < bp - 1 ) fputs(", ", out);
+ }
+ fputs(") ", out);
+ /* Put out the argument declarations */
+ for ( ap = breaks+2; ap <= bp; ap += 2 ) (*ap)[-1] = ';';
+ fputs(breaks[0], out);
+ free((char *)breaks);
+ return 0;
+}
diff --git a/example.c b/example.c
new file mode 100644
index 000000000..830f26da8
--- /dev/null
+++ b/example.c
@@ -0,0 +1,360 @@
+/* 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.
+ */
+
+#include <png.h>
+
+/* check to see if a file is a png file using png_check_sig() */
+int check_png(char *file_name)
+{
+ FILE *fp;
+ char buf[8];
+ int ret;
+
+ fp = fopen(file_name, "rb");
+ if (!fp)
+ return 0;
+ ret = fread(buf, 1, 8, fp);
+ fclose(fp);
+
+ if (ret != 8)
+ return 0;
+
+ ret = png_check_sig(buf, 8);
+
+ return (ret);
+}
+
+/* read a png file. You may want to return an error code if the read
+ fails (depending upon the failure). */
+void read_png(char *file_name)
+{
+ FILE *fp;
+ png_struct *png_ptr;
+ png_info *info_ptr;
+
+ /* open the file */
+ fp = fopen(file_name, "rb");
+ if (!fp)
+ return;
+
+ /* allocate the necessary structures */
+ png_ptr = malloc(sizeof (png_struct));
+ if (!png_ptr)
+ {
+ fclose(fp);
+ return;
+ }
+
+ info_ptr = malloc(sizeof (png_info));
+ if (!info_ptr)
+ {
+ fclose(fp);
+ free(png_ptr);
+ return;
+ }
+
+ /* set error handling */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_read_destroy(png_ptr, info_ptr, (png_info *)0);
+ fclose(fp);
+ free(png_ptr);
+ free(info_ptr);
+ /* If we get here, we had a problem reading the file */
+ return;
+ }
+
+ /* initialize the structures, info first for error handling */
+ png_info_init(info_ptr);
+ png_read_init(png_ptr);
+
+ /* set up the input control */
+ png_init_io(png_ptr, fp);
+
+ /* read the file information */
+ png_read_info(png_ptr, info_ptr);
+
+ /* allocate the memory to hold the image using the fields
+ of png_info. */
+
+ /* set up the transformations you want. Note that these are
+ all optional. Only call them if you want them */
+
+ /* expand paletted colors into true rgb */
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ info_ptr->bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ /* expand grayscale images to the full 8 bits */
+ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
+ info_ptr->bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ /* expand images with transparency to full alpha channels */
+ if (info_ptr->valid & PNG_INFO_tRNS)
+ png_set_expand(png_ptr);
+
+ /* Set the background color to draw transparent and alpha
+ images over */
+ png_color_16 my_background;
+
+ if (info_ptr->valid & PNG_INFO_bKGD)
+ png_set_background(png_ptr, &(info_ptr->background),
+ PNG_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_GAMMA_SCREEN, 0, 1.0);
+
+ /* tell libpng to handle the gamma conversion for you */
+ if (info_ptr->valid & PNG_INFO_gAMA)
+ png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45);
+
+ /* tell libpng to strip 16 bit depth files down to 8 bits */
+ if (info_ptr->bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+ /* dither rgb files down to 8 bit palettes & reduce palettes
+ to the number of colors available on your screen */
+ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (info_ptr->valid & PNG_INFO_PLTE)
+ png_set_dither(png_ptr, info_ptr->palette,
+ info_ptr->num_palette, max_screen_colors,
+ info_ptr->histogram);
+ 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);
+ }
+ }
+
+ /* invert monocrome files */
+ if (info_ptr->bit_depth == 1 &&
+ info_ptr->color_type == PNG_COLOR_GRAY)
+ png_set_invert(png_ptr);
+
+ /* shift the pixels down to their true bit depth */
+ if (info_ptr->valid & PNG_INFO_sBIT &&
+ info_ptr->bit_depth > info_ptr->sig_bit)
+ png_set_shift(png_ptr, &(info_ptr->sig_bit));
+
+ /* pack pixels into bytes */
+ if (info_ptr->bit_depth < 8)
+ png_set_packing(png_ptr);
+
+ /* flip the rgb pixels to bgr */
+ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+ info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+ /* swap bytes of 16 bit files to least significant bit first */
+ if (info_ptr->bit_depth == 16)
+ png_set_swap(png_ptr);
+
+ /* add a filler byte to store rgb files as rgbx */
+ if (info_ptr->bit_depth == 8 &&
+ info_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ png_set_rgbx(png_ptr);
+
+ /* optional call to update palette with transformations */
+ png_start_read_image(png_ptr);
+
+ /* the easiest way to read the image */
+ void *row_pointers[height];
+ png_read_image(png_ptr, row_pointers);
+
+ /* the other way to read images - deal with interlacing */
+
+ /* turn on interlace handling */
+ if (info_ptr->interlace_type)
+ number_passes = png_set_interlace_handling(png_ptr);
+ else
+ number_passes = 1;
+
+ for (pass = 0; pass < number_passes; pass++)
+ {
+ /* Read the image using the "sparkle" effect. */
+ png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
+
+ /* If you are only reading on row at a time, this works */
+ for (y = 0; y < height; y++)
+ {
+ char *row_pointers = row[y];
+ png_read_rows(png_ptr, &row_pointers, NULL, 1);
+ }
+
+ /* to get the rectangle effect, use the third parameter */
+ png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
+
+ /* if you want to display the image after every pass, do
+ so here */
+ }
+
+ /* read the rest of the file, getting any additional chunks
+ in info_ptr */
+ png_read_end(png_ptr, info_ptr);
+
+ /* clean up after the read, and free any memory allocated */
+ png_read_destroy(png_ptr, info_ptr, (png_info *)0);
+
+ /* free the structures */
+ free(png_ptr);
+ free(info_ptr);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return;
+}
+
+/* write a png file */
+void write_png(char *file_name, ... other image information ...)
+{
+ FILE *fp;
+ png_struct *png_ptr;
+ png_info *info_ptr;
+
+ /* open the file */
+ fp = fopen(file_name, "wb");
+ if (!fp)
+ return;
+
+ /* allocate the necessary structures */
+ png_ptr = malloc(sizeof (png_struct));
+ if (!png_ptr)
+ {
+ fclose(fp);
+ return;
+ }
+
+ info_ptr = malloc(sizeof (png_info));
+ if (!info_ptr)
+ {
+ fclose(fp);
+ free(png_ptr);
+ return;
+ }
+
+ /* set error handling */
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_write_destroy(png_ptr);
+ fclose(fp);
+ free(png_ptr);
+ free(info_ptr);
+ /* If we get here, we had a problem reading the file */
+ return;
+ }
+
+ /* initialize the structures */
+ png_info_init(info_ptr);
+ png_write_init(png_ptr);
+
+ /* set up the output control */
+ png_init_io(png_ptr, fp);
+
+ /* set the file information here */
+ info_ptr->width = ;
+ info_ptr->height = ;
+ etc.
+
+ /* set the palette if there is one */
+ info_ptr->valid |= PNG_INFO_PLTE;
+ info_ptr->palette = malloc(256 * sizeof (png_color));
+ info_ptr->num_palette = 256;
+ ... set palette colors ...
+
+ /* optional significant bit chunk */
+ info_ptr->valid |= PNG_INFO_sBIT;
+ info_ptr->sig_bit = true_bit_depth;
+
+ /* optional gamma chunk */
+ info_ptr->valid |= PNG_INFO_gAMA;
+ info_ptr->gamma = gamma;
+
+ /* other optional chunks */
+
+ /* write the file information */
+ png_write_info(png_ptr, info_ptr);
+
+ /* 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(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, &(info_ptr->sig_bit));
+
+ /* pack pixels into bytes */
+ png_set_packing(png_ptr);
+
+ /* flip bgr pixels to rgb */
+ png_set_bgr(png_ptr);
+
+ /* swap bytes of 16 bit files to most significant bit first */
+ png_set_swap(png_ptr);
+
+ /* get rid of filler bytes, pack rgb into 3 bytes */
+ png_set_rgbx(png_ptr);
+
+ /* the easiest way to write the image */
+ void *row_pointers[height];
+ png_write_image(png_ptr, row_pointers);
+
+ /* the other way to write the image - deal with interlacing */
+
+ /* turn on interlace handling */
+ if (interlacing)
+ number_passes = png_set_interlace_handling(png_ptr);
+ else
+ number_passes = 1;
+
+ for (pass = 0; pass < number_passes; pass++)
+ {
+ /* Write a few rows at a time. */
+ png_write_rows(png_ptr, row_pointers, number_of_rows);
+
+ /* If you are only writing one row at a time, this works */
+ for (y = 0; y < height; y++)
+ {
+ char *row_pointers = row[y];
+ png_write_rows(png_ptr, &row_pointers, 1);
+ }
+ }
+
+ /* write the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+
+ /* clean up after the write, and free any memory allocated */
+ png_write_destroy(png_ptr);
+
+ /* if you malloced the palette, free it here */
+ if (info_ptr->palette)
+ free(info_ptr->palette);
+
+ /* free the structures */
+ free(png_ptr);
+ free(info_ptr);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return;
+}
+
diff --git a/libpng.txt b/libpng.txt
new file mode 100644
index 000000000..4ddd1c1ad
--- /dev/null
+++ b/libpng.txt
@@ -0,0 +1,821 @@
+libpng.txt - a description on how to use and modify libpng
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+
+This file describes how to use and modify the PNG reference library
+(known as libpng) for your own use. There are four sections to this
+file: reading, writing, modifying, and configuration notes for various
+special platforms. Other then this file, the 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.
+
+Libpng was written as a companion to the PNG specification, as a
+way to reduce the amount of time and effort it takes to support
+the PNG file format in application programs. Most users will not
+have to modify the library significantly; advanced users may want
+to modify it more. The library was coded for both users. 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 bit, 32 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.txt file), libpng should cover the
+majority of the needs of it's users.
+
+Libpng uses zlib for its compression and decompression of PNG files.
+The zlib compression utility is a general purpose utility that is
+useful for more then PNG files, and can be used without libpng for
+whatever use you want. See the documentation delivered with zlib for
+more details.
+
+Those people who do not need to modify libpng should still read at
+least part of the PNG specification. The most important parts are
+the data formats and the chunk descriptions. Those who will be
+making changes to libpng should read the whole specification.
+
+The 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 the general user except as
+the first variable passed to every png function call.
+
+The png_info structure is designed to provide information about the
+png file. All of it's fields are intended to be examined or modified
+by the user. See png.h for a good description of the png_info fields.
+
+And while I'm on the topic, make sure you include the png header file:
+
+#include <png.h>
+
+Checking PNG files:
+
+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.
+
+ fread(header, 1, number, fp);
+ is_png = png_check_sig(header, number);
+
+Reading PNG files:
+
+The first thing you need to do while reading a PNG file is to allocate
+and initialize png_struct and png_info. As these are both 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 malloc returns NULL.
+
+ png_struct *png_ptr = malloc(sizeof (png_struct));
+ if (!png_ptr)
+ return;
+ png_info *info_ptr = malloc(sizeof (png_info));
+ if (!info_ptr)
+ {
+ free(png_ptr);
+ return;
+ }
+
+You may also want to do any i/o initialization here, before
+you get into libpng, so if it doesn't work, you don't have
+much to undo.
+
+ FILE *fp = fopen(file_name, "rb");
+ if (!fp)
+ {
+ free(png_ptr);
+ free(info_ptr);
+ return;
+ }
+
+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 jmpbuf field of your png_struct. 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 information on setjmp/longjmp. See
+the discussion on png error handling in the Customizing Libpng
+section below for more information on the png error handling.
+If an error occurs, and libpng longjmp's back to your setjmp,
+you will want to call png_read_destroy() to free any memory.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_read_destroy(png_ptr, info_ptr, (png_info *)0);
+ /* free pointers before returning, if necessary */
+ free(png_ptr);
+ free(info_ptr);
+ fclose(fp);
+ return;
+ }
+
+Next, you will need to call png_read_init() and png_info_init().
+These functions make sure all the fields are initialized to useful
+values, and, in the case of png_read_init(), and allocate any memory
+needed for internal uses. You must call png_info_init() first, as
+png_read_init() could do a longjmp, and if the info is not initialized,
+the png_read_destroy() could try to png_free() random addresses, which
+would be bad.
+
+ png_info_init(info_ptr);
+ png_read_init(png_ptr);
+
+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, see the discussion on png i/o handling in the
+Customizing Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+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);
+
+The png_info structure is now filled in with all the data necessary
+to read the file. Some of the more important parts of the png_info are:
+ width - holds the width of the file
+ height - holds the height of the file
+ bit_depth - holds the bit depth of one of the image channels
+ color_type - describes the channels and what they mean
+ see the PNG_COLOR_TYPE_ macros for more information
+ channels - number of channels of info for the color type
+ pixel_depth - bits per pixel
+ rowbytes - number of bytes needed to hold a row
+ interlace_type - currently 0 for none, 1 for interlaced
+ valid - this details which optional chunks were found in the file
+ to see if a chunk was present, OR valid with the appropriate
+ PNG_INFO_<chunk name> define.
+ palette and num_palette - the palette for the file
+ gamma - the gamma the file is written at
+ sig_bit and sig_bit_number - the number of significant bits
+ trans, trans_values, and number_trans - transparency info
+ hist - histogram of palette
+ text and num_text - text comments in the file.
+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, rgbx, xrgb, graph_to_rgb, etc.).
+
+A quick word about text and num_text. PNG stores comments in
+keyword/text pairs, one pair per chunk. While there are
+suggested keywords, there is no requirement to restrict the use
+to these strings. There is a requirement to have at least one
+character for a keyword. It is strongly suggested that keywords
+be sensible to humans (that's the point), so don't use abbreviations.
+See the png specification for more details. There is no requirement
+to have text after the keyword on tEXt chunks. However, you must
+have text after the keyword on zTXt chunks, as only the text gets
+compressed, and compressing nothing will result in an error.
+
+There is no maximum length on the keyword, and nothing
+prevents you from duplicating the keyword. The text field 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 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
+occur. This is important, as some of these change the color type
+and bit depth of the data, and some others only work on certain
+color types and bit depths. Even though each transformation should
+check to see if it has data that it can do somthing 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.
+
+This transforms bit depths of less then 8 to 8 bits, changes paletted
+images to rgb, and adds an alpha channel if there is transparency
+information in a tRNS chunk. This is probably most useful on grayscale
+images with bit depths of 2 or 4 and tRNS chunks.
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ info_ptr->bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
+ info_ptr->bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ if (info_ptr->valid & PNG_INFO_tRNS)
+ png_set_expand(png_ptr);
+
+This handles alpha and transparency by replacing it with a background
+value. If there was a valid one in the file, you can use it if you
+want. However, you can replace it with your own if you want also. If
+there wasn't one in the file, you must supply a color. If libpng is
+doing gamma correction, you will need to tell libpng where the
+background came from so it can do the appropriate gamma correction.
+If you are modifying the color data with png_set_expand(), you must
+indicate whether the background needs to be expanded. See the
+function definition in png.h for more details.
+
+ png_color_16 my_background;
+
+ if (info_ptr->valid & PNG_INFO_bKGD)
+ png_set_backgrond(png_ptr, &(info_ptr->background),
+ PNG_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_GAMMA_SCREEN, 0, 1.0);
+
+This handles gamma transformations of the data. Pass both the file
+gamma and the desired screen gamma. If the file does not have a
+gamma value, you can pass one anyway if you wish. Note that file
+gammas are inverted from screen gammas. See the discussions on
+gamma in the PNG specification for more information.
+
+ if (info_ptr->valid & PNG_INFO_gAMA)
+ png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45);
+
+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 (info_ptr->bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+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, this
+function 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 an histogram, it will
+use it to make intelligent choises when reducing the palette. If
+there is no histogram, it may not do a good job.
+
+ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (info_ptr->valid & PNG_INFO_PLTE)
+ png_set_dither(png_ptr, info_ptr->palette,
+ info_ptr->num_palette, max_screen_colors,
+ info_ptr->histogram);
+ 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);
+ }
+ }
+
+PNG files describe monocrome as black is zero and white is one. If you
+want this reversed (black is one and white is zero), call this:
+
+ if (info_ptr->bit_depth == 1 &&
+ info_ptr->color_type == PNG_COLOR_GRAY)
+ png_set_invert(png_ptr);
+
+PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. However,
+they also provide a way to describe the true bit depth of the image.
+Then they require bits to be scaled to full range for the bit depth
+used in the file. If you want to reduce your pixels back down to
+the true bit depth, call this:
+
+ if (info_ptr->valid & PNG_INFO_sBIT)
+ png_set_shift(png_ptr, &(info_ptr->sig_bit));
+
+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 you would rather these were expanded to 1 pixel per byte without
+changing the values of the pixels, call this:
+
+ if (info_ptr->bit_depth < 8)
+ png_set_packing(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. If you would
+rather have the pixels as blue, green, red, call this.
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+ info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
+rgb. If you need this, call this:
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+ info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+PNG files store 16 bit pixels in network byte order (most significant
+bit first). If you would rather store them the other way, (the way
+PC's store them, for example), call this:
+
+ if (info_ptr->bit_depth == 16)
+ png_set_swap(png_ptr);
+
+PNG files store rgb pixels packed into 3 bytes. If you would rather
+pack them into 4 bytes, with the filler byte last, call this:
+
+ if (info_ptr->bit_depth == 8 &&
+ info_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ png_set_rgbx(png_ptr);
+
+If you need the filler byte first, call this:
+
+ if (info_ptr->bit_depth == 8 &&
+ info_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ png_set_xrgb(png_ptr);
+
+After setting the transformations, you can update your palette by
+calling png_start_read_image(). This function is provided for those
+who need an updated palette before they read the image data. If you
+don't call this function, the library will automatically call it
+before it reads the first row.
+
+ png_start_read_image(png_ptr);
+
+That's it for the transformations. Now 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:
+
+ void *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to read the whole image in at once, you can
+use png_read_rows() instead. If there is no interlacing (check
+info_ptr->interlace_type), this is simple:
+
+ png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
+
+row_pointers is the same as in the png_read_image() call.
+
+If you are just calling one row at a time, you can do this for
+row_pointers:
+
+ char *row_pointers = row;
+
+ png_read_rows(png_ptr, &row_pointers, NULL, 1);
+
+When the file is interlaced (info_ptr->interlace_type == 1), things
+get a good deal harder. PNG files have a complicated interlace scheme
+that breaks down an image into seven smaller images of varying size.
+Libpng will fill out those images if you want, or it will give them
+to you "as is". If you want to fill them out, there is 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. 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 draw 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. Some
+examples to help clear this up:
+
+If you don't want libpng to handle the interlacing details, just
+call png_read_rows() the correct number of times to read in all
+seven images. See the PNG specification for more details on the
+interlacing scheme.
+
+If you want libpng to expand the images, call this:
+
+ if (info_ptr->interlace_type)
+ number_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,
+when it will return one.
+
+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_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, you should
+pass the png_info pointer from the png_read_info() call. If you
+are not interested, you can pass NULL.
+
+ png_read_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_read_destroy(png_ptr, info_ptr, (png_info *)0);
+
+After that, you can discard the structures, or reuse them another
+read or write. For a more compact example of reading a PNG image,
+see the file example.c.
+
+
+Writing PNG files:
+
+Much of this is very similar to reading. However, everything of
+importance is repeated here, so you don't have to constantly look
+back up in the Reading PNG files section to understand writing.
+
+The first thing you need to do while writing a PNG file is to allocate
+and initialize png_struct and png_info. As these are both large, you
+may not want to store these on the stack, unless you have stack space
+to spare.
+
+ png_struct *png_ptr = malloc(sizeof (png_struct));
+ if (!png_ptr)
+ return;
+ png_info *info_ptr = malloc(sizeof (png_info));
+ if (!info_ptr)
+ {
+ free(png_ptr);
+ return;
+ }
+
+You may also want to do any i/o initialization here, before
+you get into libpng, so if it doesn't work, you don't have
+much to undo.
+
+ FILE *fp = fopen(file_name, "wb");
+ if (!fp)
+ {
+ free(png_ptr);
+ free(info_ptr);
+ return;
+ }
+
+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 jmpbuf field of your png_struct. 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 png error handling in the Customizing Libpng
+section below for more information on the png error handling.
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_write_destroy(png_ptr);
+ /* free pointers before returning. Make sure you clean up
+ anything else you've done. */
+ free(png_ptr);
+ free(info_ptr);
+ fclose(fp);
+ return;
+ }
+
+Next, you will need to call png_write_init() and png_info_init().
+These functions make sure all the fields are initialized to useful
+values, and, in the case of png_write_init(), allocate any memory
+needed for internal uses. Do png_info_init() first, so if
+png_write_init() longjmps, you know info_ptr is valid, so you
+don't free random memory pointers, which would be bad.
+
+ png_info_init(info_ptr);
+ png_write_init(png_ptr);
+
+Now you need to set up the input 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. If you wish to handle writing
+data in another way, see the discussion on png i/o handling in the
+Customizing Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+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. See png_write_end() for more information on that. If you
+wish to write them before the image, fill them in now. If you want to
+wait until after the data, don't fill them until png_write_end(). For
+all the fields in png_info, see png.h. For explinations of what the
+fields contain, see the PNG specification. Some of the more important
+parts of the png_info are:
+ width - holds the width of the file
+ height - holds the height of the file
+ bit_depth - holds the bit depth of one of the image channels
+ color_type - describes the channels and what they mean
+ see the PNG_COLOR_TYPE_ defines for more information
+ interlace_type - currently 0 for none, 1 for interlaced
+ valid - this describes which optional chunks to write to the
+ file. Note that if you are writing a PNG_COLOR_TYPE_PALETTE
+ file, the PLTE chunk is not optional, but must still be marked
+ for writing. To mark chunks for writing, OR valid with the
+ appropriate PNG_INFO_<chunk name> define.
+ palette and num_palette - the palette for the file
+ gamma - the gamma the file is written at
+ sig_bit and sig_bit_number - the number of significant bits
+ trans, trans_values, and number_trans - transparency info
+ hist - histogram of palette
+ text and num_text - text comments in the file.
+
+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 -1. Until text gets
+arount 1000 bytes, it is not worth compressing it.
+
+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 recomendations
+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 can not contain NUL characters,
+and should not contain control characters. Text in general should
+not contain control characters. 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.
+
+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 read 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
+occur. This is important, as some of these change the color type
+and bit depth of the data, and some others only work on certain
+color types and bit depths. Even though each transformation should
+check to see if it has data that it can do somthing 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 bytes. If you would rather
+supply the pixels as 4 bytes per pixel, with the filler byte last,
+call this:
+
+ png_set_rgbx(png_ptr);
+
+If your filler byte goes first, call this:
+
+ png_set_xrgb(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.
+If you would rather supply the data 1 pixel per byte, but with the
+values limited to the correct number of bits, call this:
+
+ 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, but is packed into the bytes correctly,
+this will scale the values to appear to be the correct bit depth.
+Make sure you write a sBIT chunk when you do this, so others, if
+they want, can reduce the values down to their true depth.
+
+ /* do this before png_write_info() */
+ info_ptr->valid |= PNG_INFO_sBIT;
+
+ /* note that you can cheat and set all the values of
+ sig_bit to true_bit_depth if you want */
+ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ info_ptr->sig_bit.red = true_bit_depth;
+ info_ptr->sig_bit.green = true_bit_depth;
+ info_ptr->sig_bit.blue = true_bit_depth;
+ }
+ else
+ {
+ info_ptr->sig_bit.gray = true_bit_depth;
+ }
+
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ info_ptr->sig_bit.alpha = true_bit_depth;
+ }
+
+ png_set_shift(png_ptr, &(info_ptr->sig_bit));
+
+PNG files store 16 bit pixels in network byte order (most significant
+bit first). If you would rather supply them the other way, (the way
+PC's store them, for example), call this:
+
+ png_set_swap(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. If you would
+rather supply the pixels as blue, green, red, call this.
+
+ png_set_bgr(png_ptr);
+
+PNG files describe moncrome as black is zero and white is one. If you
+would rather supply the pixels with this reversed (black is one and
+white is zero), call this:
+
+ png_set_invert(png_ptr);
+
+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:
+
+ void *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you can'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 calling one row at a time, you can do this for
+row_pointers:
+
+ char *row_pointers = row;
+
+ png_write_rows(png_ptr, &row_pointers, 1);
+
+When the file is interlaced, things can get a good deal harder.
+PNG files have a complicated interlace scheme that breaks down an
+image into seven smaller images of varying size. Libpng will
+build these images if you want, 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
+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:
+
+ number_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 image number_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 the an appropriately filled png_info pointer. If you
+are not interested, you can pass NULL. Be careful that you don't
+write the same text or time chunks here as you did in png_write_info().
+
+ png_write_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_write_destroy(png_ptr);
+
+Any data you allocated for png_info, you must free yourself.
+
+After that, you can discard the structures, or reuse them another
+read or write. For a more compact example of writing a PNG image,
+see the file example.c.
+
+
+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 the routines in pngstub.c. The file as plenty of comments
+describing each function and how it expects to work, so I will just
+summarize here. See pngstub.c for more details.
+
+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 then that. If your pointers can't access more then 64K at a
+time, you will want to set MAXSEG_64K in zlib.h.
+
+Input/Output in libpng is done throught 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
+this, make the appropriate changes in pngstub.c and png.h. Make sure you
+change the function prototype for png_init_io() if you are no longer
+using a FILE *.
+
+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 it's caller. Currently, this is handled via
+setjmp() and longjmp(), but you could change this to do things like
+exit() if you should wish. Similarly, both png_error() and png_warning()
+print a message on stderr, but that can also be changed. 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. 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 similar.
+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.
+
+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 more simple 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 will probably need to change the png__large_malloc() and
+png_large_free() routines in pngstub.c, as these are requred
+to allocate 64K. 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 accessable. So limit zlib
+and libpng to 64K by defining MAXSEG_64K.
+
+Configuring for gui/windowing platforms:
+
+You will need to change the error message display in png_error() and
+png_warning() to display a message instead of fprinting it to stderr.
+You may want to write a single function to do this and call it something
+like png_message(). On some compliers, you may have to change the
+memory allocators (png_malloc, etc.).
+
+Configuring for compiler xxx:
+
+All includes for libpng are in png.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.
+
diff --git a/makefile b/makefile
new file mode 100644
index 000000000..5d3da0f0b
--- /dev/null
+++ b/makefile
@@ -0,0 +1,49 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=gcc
+CFLAGS=-I../zlib -O3
+LDFLAGS=-L. -L../zlib/ -lpng -lgz -lm
+
+RANLIB=ranlib
+#RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngstub.o pngwrite.o pngrtran.o pngwtran.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ cc -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+pngrcb.o: png.h
+pngread.o: png.h
+pngrtran.o: png.h
+pngrutil.o: png.h
+pngstub.o: png.h
+pngtest.o: png.h
+pngtrans.o: png.h
+pngwrite.o: png.h
+pngwtran.o: png.h
+pngwutil.o: png.h
diff --git a/makefile.knr b/makefile.knr
new file mode 100644
index 000000000..5eb0b79ac
--- /dev/null
+++ b/makefile.knr
@@ -0,0 +1,61 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=cc
+CFLAGS=-I../zlib -O
+LDFLAGS=-L. -L../zlib/ -lpng -lgz -lm
+# flags for ansi2knr
+ANSI2KNRFLAGS=
+
+RANLIB=ranlib
+#RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngstub.o pngwrite.o pngrtran.o pngwtran.o
+
+all: ansi2knr libpng.a pngtest
+
+# general rule to allow ansi2knr to work
+.c.o:
+ ./ansi2knr $*.c T$*.c
+ $(CC) $(CFLAGS) -c T$*.c
+ rm -f T$*.c $*.o
+ mv T$*.o $*.o
+
+ansi2knr: ansi2knr.c
+ $(CC) $(CFLAGS) $(ANSI2KNRFLAGS) -o ansi2knr ansi2knr.c
+
+libpng.a: ansi2knr $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a ansi2knr
+ cc -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png ansi2knr
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+pngrcb.o: png.h
+pngread.o: png.h
+pngrtran.o: png.h
+pngrutil.o: png.h
+pngstub.o: png.h
+pngtest.o: png.h
+pngtrans.o: png.h
+pngwrite.o: png.h
+pngwtran.o: png.h
+pngwutil.o: png.h
diff --git a/makefile.mip b/makefile.mip
new file mode 100644
index 000000000..ea41c611d
--- /dev/null
+++ b/makefile.mip
@@ -0,0 +1,50 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=cc
+CFLAGS=-I../zlib -O -systype sysv -DSYSV -w -Dmips
+#CFLAGS=-O
+LDFLAGS=-L. -L../zlib/ -lpng -lgz -lm
+
+#RANLIB=ranlib
+RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngstub.o pngwrite.o pngrtran.o pngwtran.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ cc -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+pngrcb.o: png.h
+pngread.o: png.h
+pngrtran.o: png.h
+pngrutil.o: png.h
+pngstub.o: png.h
+pngtest.o: png.h
+pngtrans.o: png.h
+pngwrite.o: png.h
+pngwtran.o: png.h
+pngwutil.o: png.h
diff --git a/makefile.std b/makefile.std
new file mode 100644
index 000000000..1613e9097
--- /dev/null
+++ b/makefile.std
@@ -0,0 +1,49 @@
+# makefile for libpng
+# Copyright (C) 1995 Guy Eric Schalnat, Group 42, Inc.
+# For conditions of distribution and use, see copyright notice in png.h
+
+CC=cc
+CFLAGS=-I../zlib -O
+LDFLAGS=-L. -L../zlib/ -lpng -lgz -lm
+
+#RANLIB=ranlib
+RANLIB=echo
+
+# where make install puts libpng.a and png.h
+prefix=/usr/local
+
+OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \
+ pngread.o pngstub.o pngwrite.o pngrtran.o pngwtran.o
+
+all: libpng.a pngtest
+
+libpng.a: $(OBJS)
+ ar rc $@ $(OBJS)
+ $(RANLIB) $@
+
+pngtest: pngtest.o libpng.a
+ cc -o pngtest $(CCFLAGS) pngtest.o $(LDFLAGS)
+
+install: libpng.a
+ -@mkdir $(prefix)/include
+ -@mkdir $(prefix)/lib
+ cp png.h $(prefix)/include
+ chmod 644 $(prefix)/include/png.h
+ cp libpng.a $(prefix)/lib
+ chmod 644 $(prefix)/lib/libpng.a
+
+clean:
+ rm -f *.o libpng.a pngtest pngout.png
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+pngrcb.o: png.h
+pngread.o: png.h
+pngrtran.o: png.h
+pngrutil.o: png.h
+pngstub.o: png.h
+pngtest.o: png.h
+pngtrans.o: png.h
+pngwrite.o: png.h
+pngwtran.o: png.h
+pngwutil.o: png.h
diff --git a/png.c b/png.c
new file mode 100644
index 000000000..d65d7c645
--- /dev/null
+++ b/png.c
@@ -0,0 +1,172 @@
+
+/* png.c - location for general purpose png functions
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#define PNG_INTERNAL
+#define PNG_NO_EXTERN
+#include "png.h"
+
+/* place to hold the signiture string for a png file. */
+png_byte 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 png_IHDR[4] = { 73, 72, 68, 82};
+png_byte png_IDAT[4] = { 73, 68, 65, 84};
+png_byte png_IEND[4] = { 73, 69, 78, 68};
+png_byte png_PLTE[4] = { 80, 76, 84, 69};
+png_byte png_gAMA[4] = {103, 65, 77, 65};
+png_byte png_sBIT[4] = {115, 66, 73, 84};
+png_byte png_cHRM[4] = { 99, 72, 82, 77};
+png_byte png_tRNS[4] = {116, 82, 78, 83};
+png_byte png_bKGD[4] = { 98, 75, 71, 68};
+png_byte png_hIST[4] = {104, 73, 83, 84};
+png_byte png_tEXt[4] = {116, 69, 88, 116};
+png_byte png_zTXt[4] = {122, 84, 88, 116};
+png_byte png_pHYs[4] = {112, 72, 89, 115};
+png_byte png_oFFs[4] = {111, 70, 70, 115};
+png_byte png_tIME[4] = {116, 73, 77, 69};
+
+/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+/* start of interlace block */
+int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+/* offset to next interlace block */
+int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+/* start of interlace block in the y direction */
+int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+/* offset to next interlace block in the y direction */
+int 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 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 png_pass_height[] = {8, 8, 4, 4, 4, 2, 2, 1};
+*/
+
+/* mask to determine which pixels are valid in a pass */
+int png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
+
+/* mask to determine which pixels to overwrite while displaying */
+int png_pass_dsp_mask[] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+
+
+int
+png_check_sig(png_byte *sig, int num)
+{
+ if (num > 8)
+ num = 8;
+ if (num < 1)
+ return 0;
+
+ return (!memcmp(sig, png_sig, num));
+}
+
+/* Function to allocate memory for zlib. */
+voidp
+png_zalloc(voidp png_ptr, uInt items, uInt size)
+{
+ return ((voidp)png_large_malloc((png_struct *)png_ptr,
+ (png_uint_32)items * (png_uint_32)size));
+}
+
+/* function to free memory for zlib */
+void
+png_zfree(voidp png_ptr, voidp ptr)
+{
+ png_large_free((png_struct *)png_ptr, (void *)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_struct *png_ptr)
+{
+ /* set crc to all 1's */
+ png_ptr->crc = 0xffffffffL;
+}
+
+/* Note: the crc code below was copied from the sample code in the
+ PNG spec, with appropriate modifications made to ensure the
+ variables are large enough */
+
+/* table of crc's of all 8-bit messages. If you wish to png_malloc this
+ table, turn this into a pointer, and png_malloc it in make_crc_table().
+ You may then want to hook it into png_struct and free it with the
+ destroy functions. */
+static png_uint_32 crc_table[256];
+
+/* Flag: has the table been computed? Initially false. */
+static int crc_table_computed = 0;
+
+/* make the table for a fast crc */
+static void
+make_crc_table(void)
+{
+ png_uint_32 c;
+ int n, k;
+
+ for (n = 0; n < 256; n++)
+ {
+ c = (png_uint_32)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? 0xedb88320L ^ (c >> 1) : c >> 1;
+ crc_table[n] = c;
+ }
+ crc_table_computed = 1;
+}
+
+/* update a running crc with the bytes buf[0..len-1]--the crc should be
+ initialized to all 1's, and the transmitted value is the 1's complement
+ of the final running crc. */
+static png_uint_32
+update_crc(png_uint_32 crc, png_byte *buf, png_uint_32 len)
+{
+ png_uint_32 c;
+ png_byte *p;
+ png_uint_32 n;
+
+ c = crc;
+ p = buf;
+ n = len;
+
+ if (!crc_table_computed)
+ {
+ make_crc_table();
+ }
+
+ if (n > 0) do
+ {
+ c = crc_table[(png_byte)((c ^ (*p++)) & 0xff)] ^ (c >> 8);
+ } while (--n);
+
+ return c;
+}
+
+/* calculate the crc over a section of data. Note that while we
+ are passing in a 32 bit value for length, on 16 bit machines, you
+ would need to use huge pointers to access all that data. If you
+ need this, put huge here and above. */
+void
+png_calculate_crc(png_struct *png_ptr, png_byte *ptr,
+ png_uint_32 length)
+{
+ png_ptr->crc = update_crc(png_ptr->crc, ptr, length);
+}
+
+
diff --git a/png.h b/png.h
new file mode 100644
index 000000000..b0fc8e582
--- /dev/null
+++ b/png.h
@@ -0,0 +1,913 @@
+
+/* png.h - header file for png reference library
+ libpng 1.0 beta 1 - version 0.71
+ June 26, 1995
+
+ Note: This is a beta version. It reads and writes valid files
+ on the platforms I have, but it has had limited portability
+ testing. Furthermore, you will probably have to modify the
+ includes below to get it to work on your system, and you
+ may have to supply the correct compiler flags in the makefile.
+ Read the readme.txt for more information, and how to contact
+ me if you have any problems, or if you want your compiler/
+ platform to be supported in the next official libpng release.
+
+ See readme.txt for more information
+
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ Contributing Authors:
+ Guy Eric Schalnat
+
+ 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 damages, direct or consequential, which may
+ result from the use of the PNG Reference Library.
+
+ 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
+
+/* 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 to build around. This file is useful for looking
+ at the actual function definitions and structure components. */
+
+/* This file is arranged in several sections. The first section contains
+ all the definitions for libpng. The second section details the functions
+ most users will use. The third section describes the stub files that
+ users will most likely need to change. The last section contains
+ functions used internally by the code.
+
+ 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 */
+
+/* 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 extreamly 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 then the size of a row (compressed),
+ it should not make much difference how big this is. */
+
+#define PNG_ZBUF_SIZE 8192;
+
+/* include the compression library's header */
+#include "zlib.h"
+
+/* While libpng currently uses zlib for it's compression, it has been designed
+ to stand on it's own. Towards this end, there are two defines that are
+ used to help portability between machines. To make it simpler to
+ setup libpng on a machine, this currently uses zlib's definitions, so
+ any changes should be made in zlib. Libpng will check zlib's settings
+ and adjust it's own accordingly. */
+
+/* if you are running on a machine where you cannot allocate more then
+ 64K of memory, 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_ALLOC_64K
+*/
+#ifdef MAXSEG_64K
+#define PNG_MAX_ALLOC_64K
+#endif
+
+/* this macro protects us against machines that don't have function
+ prototypes. If your compiler does not handle function prototypes,
+ define this macro. 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 __P
+#define PNGARG(arglist) __P(arglist)
+#else
+
+#ifdef _NO_PROTO
+#define PNGARG(arglist)
+#else
+#define PNGARG(arglist) arglist
+#endif /* _NO_PROTO */
+
+#endif /* __P(arglist) */
+
+#endif /* PNGARG */
+
+/* enough people need this for various reasons to include it here */
+#include <sys/types.h>
+/* need the time information for reading tIME chunks */
+#include <time.h>
+
+/* for FILE. If you are not using standard io, you don't need this */
+#include <stdio.h>
+
+/* include setjmp.h for error handling */
+#include <setjmp.h>
+
+/* other defines for things like memory and the like can go here. These
+ are the only files included in libpng, so if you need to change them,
+ change them here. They are only included if PNG_INTERNAL is defined. */
+#ifdef PNG_INTERNAL
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef BSD
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+#include <math.h>
+
+/* other defines specific to compilers can go here. Try to keep
+ them inside an appropriate ifdef/endif pair for portability */
+
+/* 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 */
+#define PNG_DITHER_RED_BITS 5
+#define PNG_DITHER_GREEN_BITS 5
+#define PNG_DITHER_BLUE_BITS 5
+
+/* 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 get this
+ value less then 8, and even that may not work (I haven't tested
+ it). */
+
+#define PNG_MAX_GAMMA_8 11
+
+#endif /* PNG_INTERNAL */
+
+/* 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. */
+
+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;
+
+/* 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). While png_color_8 and
+ png_color_16 have more fields then they need, they are never used in
+ arrays, so the size isn't that important. I thought about using
+ unions, but it looked too clumsy, so I left it. If you're using C++,
+ you can union red, index, and gray, if you want. */
+typedef struct png_color_struct
+{
+ png_byte red;
+ png_byte green;
+ png_byte blue;
+} png_color;
+
+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 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;
+
+/* png_text holds the text in a png file, and whether they are compressed
+ or not. If compression is -1, the text is not compressed. */
+typedef struct png_text_struct
+{
+ int compression; /* compression value, -1 if uncompressed */
+ char *key; /* keyword */
+ char *text; /* comment */
+ png_uint_32 text_length; /* length of text field */
+} png_text;
+
+/* 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. */
+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;
+
+/* png_info is a structure that holds the information in a png file.
+ 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. */
+typedef struct png_info_struct
+{
+ /* the following are necessary for every png file */
+ png_uint_32 width; /* with of file */
+ png_uint_32 height; /* height of file */
+ png_byte bit_depth; /* 1, 2, 4, 8, or 16 */
+ png_byte color_type; /* use the PNG_COLOR_TYPE_ defines */
+ png_byte compression_type; /* must be 0 */
+ png_byte filter_type; /* must be 0 */
+ png_byte interlace_type; /* 0 for non-interlaced, 1 for interlaced */
+ png_uint_32 valid; /* the PNG_INFO_ defines, OR'd together */
+ /* the following is informational only on read, and not used on
+ writes */
+ png_byte channels; /* number of channels of data per pixel */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_uint_32 rowbytes; /* bytes needed for untransformed row */
+ /* the rest are 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 */
+ float gamma; /* gamma value of file, if gAMA chunk is valid */
+ png_color_8 sig_bit; /* significant bits */
+ float x_white; /* cHRM chunk values */
+ float y_white;
+ float x_red;
+ float y_red;
+ float x_green;
+ float y_green;
+ float x_blue;
+ float y_blue;
+ png_color *palette; /* palette of file */
+ png_uint_16 num_palette; /* number of values in palette */
+ png_byte *trans; /* tRNS values for palette image */
+ png_uint_16 num_trans; /* number of trans values */
+ png_color_16 trans_values; /* tRNS values for non-palette image */
+ png_color_16 background; /* background color of image */
+ png_uint_16 *hist; /* histogram of palette usage */
+ png_uint_32 x_pixels_per_unit; /* x resolution */
+ png_uint_32 y_pixels_per_unit; /* y resolution */
+ png_byte phys_unit_type; /* resolution type */
+ 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 */
+ png_time mod_time; /* modification time */
+ int num_text; /* number of comments */
+ int max_text; /* size of text array */
+ png_text *text; /* array of comments */
+} png_info;
+
+#define PNG_RESOLUTION_UNKNOWN 0
+#define PNG_RESOLUTION_METER 1
+
+#define PNG_OFFSET_PIXEL 0
+#define PNG_OFFSET_MICROMETER 1
+
+/* 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_PALETTE \
+ (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_GRAY 0
+#define PNG_COLOR_TYPE_RGB_ALPHA \
+ (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
+
+/* These determine if a chunks information is present in a read operation, or
+ if the chunk should be written in a write operation. */
+#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
+
+/* 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 uses. */
+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;
+
+/* 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.
+ */
+typedef struct png_struct_def
+{
+ jmp_buf jmpbuf; /* used in png_error */
+ png_byte mode; /* used to determine where we are in the png file */
+ png_byte color_type; /* color type of file */
+ png_byte bit_depth; /* bit depth of file */
+ png_byte interlaced; /* interlace type of file */
+ png_byte compession; /* compression type of file */
+ png_byte filter; /* filter type */
+ png_byte channels; /* number of channels in file */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte usr_bit_depth; /* bit depth of users row */
+ png_byte usr_channels; /* channels at start of write */
+ png_byte gamma_shift; /* amount of shift for 16 bit gammas */
+ png_byte pass; /* current pass (0 - 6) */
+ png_byte row_init; /* 1 if png_read_start_row() has been called */
+ png_byte background_gamma_type;
+ png_byte background_expand;
+ png_byte zlib_finished;
+ png_byte user_palette;
+ png_uint_16 num_palette; /* number of entries in palette */
+ png_uint_16 num_trans; /* number of transparency values */
+ png_uint_32 transformations; /* which transformations to perform */
+ png_uint_32 crc; /* current crc value */
+ png_uint_32 width; /* width of file */
+ png_uint_32 height; /* height of file */
+ png_uint_32 num_rows; /* number of rows in current pass */
+ png_uint_32 rowbytes; /* size of row in bytes */
+ png_uint_32 usr_width; /* width of row at start of write */
+ png_uint_32 iwidth; /* interlaced width */
+ png_uint_32 irowbytes; /* interlaced rowbytes */
+ png_uint_32 row_number; /* current row in pass */
+ png_uint_32 idat_size; /* current idat size for read */
+ png_uint_32 zbuf_size; /* size of zbuf */
+ png_color *palette; /* files palette */
+ png_byte *palette_lookup; /* lookup table for dithering */
+ png_byte *gamma_table; /* gamma table for 8 bit depth files */
+ png_byte *gamma_from_1; /* converts from 1.0 to screen */
+ png_byte *gamma_to_1; /* converts from file to 1.0 */
+ png_byte *trans; /* transparency values for paletted files */
+ png_byte *dither_index; /* index translation for palette files */
+ png_uint_16 **gamma_16_table; /* gamma table for 16 bit depth files */
+ png_uint_16 **gamma_16_from_1; /* converts from 1.0 to screen */
+ png_uint_16 **gamma_16_to_1; /* converts from file to 1.0 */
+ png_uint_16 *hist; /* histogram */
+ png_byte *zbuf; /* buffer for zlib */
+ png_byte *row_buf; /* row buffer */
+ png_byte *prev_row; /* previous row */
+ png_byte *save_row; /* place to save row before filtering */
+ z_stream *zstream; /* pointer to decompression structure (below) */
+ float gamma; /* file gamma value */
+ float display_gamma; /* display gamma value */
+ float background_gamma;
+ png_color_8 shift; /* shift for significant bit tranformation */
+ png_color_8 sig_bit; /* significant bits in file */
+ png_color_16 trans_values; /* transparency values for non-paletted files */
+ png_color_16 background; /* background color, gamma corrected for screen */
+ png_color_16 background_1; /* background normalized to gamma 1.0 */
+ png_row_info row_info; /* used for transformation routines */
+ z_stream zstream_struct; /* decompression structure */
+ FILE *fp; /* used for png_read and png_write */
+} png_struct;
+
+
+/* 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. */
+
+/* check the first 1 - 8 bytes to see if it is a png file */
+extern int png_check_sig PNGARG((png_byte *sig, int num));
+
+/* initialize png structure for reading, and allocate any memory needed */
+extern void png_read_init PNGARG((png_struct *png_ptr));
+
+/* initialize png structure for writing, and allocate any memory needed */
+extern void png_write_init PNGARG((png_struct *png_ptr));
+
+/* initialize the info structure */
+extern void png_info_init PNGARG((png_info *info));
+
+/* Writes all the png information before the image. */
+extern void png_write_info PNGARG((png_struct *png_ptr, png_info *info));
+
+/* read the information before the actual image data. */
+extern void png_read_info PNGARG((png_struct *png_ptr, png_info *info));
+
+/* convert from a struct tm to png_time */
+extern void png_convert_from_struct_tm PNGARG((png_time *ptime,
+ struct tm *ttime));
+
+/* convert from time_t to png_time. Uses gmtime() */
+extern void png_convert_from_time_t PNGARG((png_time *ptime, time_t ttime));
+
+/* Expand the data to 24 bit RGB, or 8 bit Grayscale,
+ with alpha if necessary. */
+extern void png_set_expand PNGARG((png_struct *png_ptr));
+
+/* Use blue, green, red order for pixels. */
+extern void png_set_bgr PNGARG((png_struct *png_ptr));
+
+/* Add a filler byte to rgb images after the colors. */
+extern void png_set_rgbx PNGARG((png_struct *png_ptr));
+
+/* Add a filler byte to rgb images before the colors. */
+extern void png_set_xrgb PNGARG((png_struct *png_ptr));
+
+/* Swap bytes in 16 bit depth files. */
+extern void png_set_swap PNGARG((png_struct *png_ptr));
+
+/* Use 1 byte per pixel in 1, 2, or 4 bit depth files. */
+extern void png_set_packing PNGARG((png_struct *png_ptr));
+
+/* Converts files to legal bit depths. */
+extern void png_set_shift PNGARG((png_struct *png_ptr,
+ png_color_8 *true_bits));
+
+/* Have the code handle the interlacing. Returns the number of passes. */
+extern int png_set_interlace_handling PNGARG((png_struct *png_ptr));
+
+/* Invert monocrome files */
+extern void png_set_invert_mono PNGARG((png_struct *png_ptr));
+
+/* Handle alpha and tRNS by replacing with a background color. */
+#define PNG_BACKGROUND_GAMMA_SCREEN 0
+#define PNG_BACKGROUND_GAMMA_FILE 1
+#define PNG_BACKGROUND_GAMMA_UNIQUE 2
+#define PNG_BACKGROUND_GAMMA_UNKNOWN 3
+extern void png_set_background PNGARG((png_struct *png_ptr,
+ png_color_16 *background_color, int background_gamma_code,
+ int need_expand, float background_gamma));
+
+/* strip the second byte of information from a 16 bit depth file. */
+extern void png_set_strip_16 PNGARG((png_struct *png_ptr));
+
+/* convert a grayscale file into rgb. */
+extern void png_set_gray_to_rgb PNGARG((png_struct *png_ptr));
+
+/* Turn on dithering, and reduce the palette to the number of colors available. */
+extern void png_set_dither PNGARG((png_struct *png_ptr, png_color *palette,
+ int num_palette, int maximum_colors, png_uint_16 *histogram, int full_dither));
+
+/* Handle gamma correction. */
+extern void png_set_gamma PNGARG((png_struct *png_ptr, float screen_gamma,
+ float default_file_gamma));
+
+/* optional update palette with requested transformations */
+void png_start_read_image PNGARG((png_struct *png_ptr));
+
+/* read a one or more rows of image data.*/
+extern void png_read_rows PNGARG((png_struct *png_ptr,
+ png_byte **row,
+ png_byte **display_row, png_uint_32 num_rows));
+
+/* read a row of data.*/
+extern void png_read_row PNGARG((png_struct *png_ptr,
+ png_byte *row,
+ png_byte *display_row));
+
+/* read the whole image into memory at once. */
+extern void png_read_image PNGARG((png_struct *png_ptr,
+ png_byte **image));
+
+/* write a row of image data */
+extern void png_write_row PNGARG((png_struct *png_ptr,
+ png_byte *row));
+
+/* write a few rows of image data */
+extern void png_write_rows PNGARG((png_struct *png_ptr,
+ png_byte **row,
+ png_uint_32 num_rows));
+
+/* write the image data */
+extern void png_write_image PNGARG((png_struct *png_ptr, png_byte **image));
+
+/* writes the end of the png file. */
+extern void png_write_end PNGARG((png_struct *png_ptr, png_info *info));
+
+/* read the end of the png file. */
+extern void png_read_end PNGARG((png_struct *png_ptr, png_info *info));
+
+/* free all memory used by the read */
+extern void png_read_destroy PNGARG((png_struct *png_ptr, png_info *info,
+ png_info *end_info));
+
+/* free any memory used in png struct */
+extern void png_write_destroy PNGARG((png_struct *png_ptr));
+
+
+/* These next functions are stubs of typical c functions for input/output,
+ memory, and error handling. They are in the file pngstub.c, and are
+ set up to be easily modified for users that need to. See the file
+ pngstub.c for more information */
+
+/* Write the data to whatever output you are using. */
+extern void png_write_data PNGARG((png_struct *png_ptr, png_byte *data,
+ png_uint_32 length));
+
+/* Read data from whatever input you are using */
+extern void png_read_data PNGARG((png_struct *png_ptr, png_byte *data,
+ png_uint_32 length));
+
+/* Initialize the input/output for the png file. */
+extern void png_init_io PNGARG((png_struct *png_ptr, FILE *fp));
+
+/* Allocate memory in larger chunks. */
+extern void *png_large_malloc PNGARG((png_struct *png_ptr, png_uint_32 size));
+
+/* free's a pointer allocated by png_large_malloc() */
+extern void png_large_free PNGARG((png_struct *png_ptr, void *ptr));
+
+/* Allocate memory. */
+extern void *png_malloc PNGARG((png_struct *png_ptr, png_uint_32 size));
+
+/* Reallocate memory. */
+extern void *png_realloc PNGARG((png_struct *png_ptr, void *ptr,
+ png_uint_32 size));
+
+/* free's a pointer allocated by png_malloc() */
+extern void png_free PNGARG((png_struct *png_ptr, void *ptr));
+
+/* Fatal error in libpng - can't continue */
+extern void png_error PNGARG((png_struct *png_ptr, char *error));
+
+/* Non-fatal error in libpng. Can continue, but may have a problem. */
+extern void png_warning PNGARG((png_struct *png_ptr, char *message));
+
+
+/* These next functions are used internally in the code. If you use
+ them, make sure you read and understand the png spec. More information
+ about them can be found in the files where the functions are.
+ Feel free to move any of these outside the PNG_INTERNAL define if
+ you just need a few of them, but if you need access to more, you should
+ define PNG_INTERNAL inside your code, so everyone who includes png.h
+ won't get yet another definition the compiler has to deal with. */
+
+#ifdef PNG_INTERNAL
+
+/* various modes of operation. Note that after an init, mode is set to
+ zero automatically */
+#define PNG_BEFORE_IHDR 0
+#define PNG_HAVE_IHDR 1
+#define PNG_HAVE_PLTE 2
+#define PNG_HAVE_IDAT 3
+#define PNG_AT_LAST_IDAT 4
+#define PNG_AFTER_IDAT 5
+#define PNG_AFTER_IEND 6
+
+/* defines 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_XRGB 0x0100
+#define PNG_16_TO_8 0x0200
+#define PNG_RGBA 0x0400
+#define PNG_EXPAND 0x0800
+#define PNG_GAMMA 0x1000
+#define PNG_GRAY_TO_RGB 0x2000
+
+/* 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 defined in png.c - only it needs to define PNG_NO_EXTERN */
+#ifndef PNG_NO_EXTERN
+/* place to hold the signiture string for a png file. */
+extern png_byte png_sig[];
+
+/* 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 */
+extern png_byte png_IHDR[];
+extern png_byte png_IDAT[];
+extern png_byte png_IEND[];
+extern png_byte png_PLTE[];
+extern png_byte png_gAMA[];
+extern png_byte png_sBIT[];
+extern png_byte png_cHRM[];
+extern png_byte png_tRNS[];
+extern png_byte png_bKGD[];
+extern png_byte png_hIST[];
+extern png_byte png_tEXt[];
+extern png_byte png_zTXt[];
+extern png_byte png_pHYs[];
+extern png_byte png_oFFs[];
+extern png_byte png_tIME[];
+/* Structures to facilitate easy interlacing. See png.c for more details */
+extern int png_pass_start[];
+extern int png_pass_inc[];
+extern int png_pass_ystart[];
+extern int png_pass_yinc[];
+/* these are not currently used. If you need them, see png.c
+extern int png_pass_width[];
+extern int png_pass_height[];
+*/
+extern int png_pass_mask[];
+extern int png_pass_dsp_mask[];
+
+#endif /* PNG_NO_EXTERN */
+
+/* Function to allocate memory for zlib. */
+extern voidp png_zalloc PNGARG((voidp png_ptr, uInt items, uInt size));
+
+/* function to free memory for zlib */
+extern void png_zfree PNGARG((voidp png_ptr, voidp ptr));
+
+/* reset the crc variable */
+extern void png_reset_crc PNGARG((png_struct *png_ptr));
+
+/* calculate the crc over a section of data. Note that while we
+ are passing in a 32 bit value for length, on 16 bit machines, you
+ would need to use huge pointers to access all that data. See the
+ code in png.c for more information. */
+extern void png_calculate_crc PNGARG((png_struct *png_ptr, png_byte *ptr,
+ png_uint_32 length));
+
+/* place a 32 bit number into a buffer in png byte order. We work
+ with unsigned numbers for convenience, you may have to cast
+ signed numbers (if you use any, most png data is unsigned). */
+extern void png_save_uint_32 PNGARG((png_byte *buf, png_uint_32 i));
+
+/* place a 16 bit number into a buffer in png byte order */
+extern void png_save_uint_16 PNGARG((png_byte *buf, png_uint_16 i));
+
+/* write a 32 bit number */
+extern void png_write_uint_32 PNGARG((png_struct *png_ptr, png_uint_32 i));
+
+/* write a 16 bit number */
+extern void png_write_uint_16 PNGARG((png_struct *png_ptr, png_uint_16 i));
+
+/* Write a png chunk. */
+extern void png_write_chunk PNGARG((png_struct *png_ptr, png_byte *type,
+ png_byte *data, png_uint_32 length));
+
+/* Write the start of a png chunk. */
+extern void png_write_chunk_start PNGARG((png_struct *png_ptr, png_byte *type,
+ png_uint_32 total_length));
+
+/* write the data of a png chunk started with png_write_chunk_start(). */
+extern void png_write_chunk_data PNGARG((png_struct *png_ptr, png_byte *data,
+ png_uint_32 length));
+
+/* finish a chunk started with png_write_chunk_start() */
+extern void png_write_chunk_end PNGARG((png_struct *png_ptr));
+
+/* simple function to write the signiture */
+extern void png_write_sig PNGARG((png_struct *png_ptr));
+
+/* write various chunks */
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ information. */
+extern void png_write_IHDR PNGARG((png_struct *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));
+
+extern void png_write_PLTE PNGARG((png_struct *png_ptr, png_color *palette,
+ int number));
+
+extern void png_write_IDAT PNGARG((png_struct *png_ptr, png_byte *data,
+ png_uint_32 length));
+
+extern void png_write_IEND PNGARG((png_struct *png_ptr));
+
+extern void png_write_gAMA PNGARG((png_struct *png_ptr, float gamma));
+
+extern void png_write_sBIT PNGARG((png_struct *png_ptr, png_color_8 *sbit,
+ int color_type));
+
+extern void png_write_cHRM PNGARG((png_struct *png_ptr,
+ float white_x, float white_y,
+ float red_x, float red_y, float green_x, float green_y,
+ float blue_x, float blue_y));
+
+extern void png_write_tRNS PNGARG((png_struct *png_ptr, png_byte *trans,
+ png_color_16 *values, int number, int color_type));
+
+extern void png_write_bKGD PNGARG((png_struct *png_ptr, png_color_16 *values,
+ int color_type));
+
+extern void png_write_hIST PNGARG((png_struct *png_ptr, png_uint_16 *hist,
+ int number));
+
+extern void png_write_tEXt PNGARG((png_struct *png_ptr, char *key,
+ char *text, png_uint_32 text_len));
+
+extern void png_write_zTXt PNGARG((png_struct *png_ptr, char *key,
+ char *text, png_uint_32 text_len, int compression));
+
+extern void png_write_pHYs PNGARG((png_struct *png_ptr,
+ png_uint_32 x_pixels_per_unit,
+ png_uint_32 y_pixels_per_unit,
+ int unit_type));
+
+extern void png_write_oFFs PNGARG((png_struct *png_ptr,
+ png_uint_32 x_offset,
+ png_uint_32 y_offset,
+ int unit_type));
+
+extern void png_write_tIME PNGARG((png_struct *png_ptr, png_time *mod_time));
+
+/* Internal use only. Called when finished processing a row of data */
+extern void png_write_finish_row PNGARG((png_struct *png_ptr));
+
+/* Internal use only. Called before first row of data */
+extern void png_write_start_row PNGARG((png_struct *png_ptr));
+
+/* callbacks for png chunks */
+extern void png_read_IHDR PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int compression_type, int filter_type,
+ int interlace_type));
+extern void png_read_PLTE PNGARG((png_struct *png_ptr, png_info *info,
+ png_color *palette, int num));
+extern void png_read_gAMA PNGARG((png_struct *png_ptr, png_info *info,
+ float gamma));
+extern void png_read_sBIT PNGARG((png_struct *png_ptr, png_info *info,
+ png_color_8 *sig_bit));
+extern void png_read_cHRM PNGARG((png_struct *png_ptr, png_info *info,
+ float white_x, float white_y, float red_x, float red_y,
+ float green_x, float green_y, float blue_x, float blue_y));
+extern void png_read_tRNS PNGARG((png_struct *png_ptr, png_info *info,
+ png_byte *trans, int num_trans, png_color_16 *trans_values));
+extern void png_read_bKGD PNGARG((png_struct *png_ptr, png_info *info,
+ png_color_16 *background));
+extern void png_read_hIST PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_16 *hist));
+extern void png_read_pHYs PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+extern void png_read_oFFs PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 offset_x, png_uint_32 offset_y, int unit_type));
+extern void png_read_tIME PNGARG((png_struct *png_ptr, png_info *info,
+ png_time *mod_time));
+extern void png_read_tEXt PNGARG((png_struct *png_ptr, png_info *info,
+ char *key, char *text, png_uint_32 text_len));
+extern void png_read_zTXt PNGARG((png_struct *png_ptr, png_info *info,
+ char *key, char *text, png_uint_32 text_len, int compression));
+
+void
+png_build_gamma_table PNGARG((png_struct *png_ptr));
+
+/* combine a row of data, dealing with alpha, etc. if requested */
+extern void png_combine_row PNGARG((png_struct *png_ptr, png_byte *row,
+ int mask));
+/* expand an interlaced row */
+extern void png_do_read_interlace PNGARG((png_row_info *row_info,
+ png_byte *row, int pass));
+/* grab pixels out of a row for an interlaced pass */
+extern void png_do_write_interlace PNGARG((png_row_info *row_info,
+ png_byte *row, int pass));
+
+/* unfilter a row */
+extern void png_read_filter_row PNGARG((png_row_info *row_info,
+ png_byte *row, png_byte *prev_row, int filter));
+/* filter a row, and place the correct filter byte in the row */
+extern void png_write_filter_row PNGARG((png_row_info *row_info,
+ png_byte *row, png_byte *prev_row));
+/* finish a row while reading, dealing with interlacing passes, etc. */
+extern void png_read_finish_row PNGARG((png_struct *png_ptr));
+/* initialize the row buffers, etc. */
+extern void png_read_start_row PNGARG((png_struct *png_ptr));
+
+/* these are the functions that do the transformations */
+extern void png_do_read_rgbx PNGARG((png_row_info *row_info,
+ png_byte *row));
+extern void png_do_write_rgbx PNGARG((png_row_info *row_info,
+ png_byte *row));
+extern void png_do_read_xrgb PNGARG((png_row_info *row_info,
+ png_byte *row));
+extern void png_do_write_xrgb PNGARG((png_row_info *row_info,
+ png_byte *row));
+extern void png_do_swap PNGARG((png_row_info *row_info, png_byte *row));
+extern void png_do_unpack PNGARG((png_row_info *row_info, png_byte *row));
+extern void png_do_unshift PNGARG((png_row_info *row_info, png_byte *row,
+ png_color_8 *sig_bits));
+extern void png_do_invert PNGARG((png_row_info *row_info, png_byte *row));
+extern void png_do_gray_to_rgb PNGARG((png_row_info *row_info,
+ png_byte *row));
+extern void png_do_chop PNGARG((png_row_info *row_info, png_byte *row));
+extern void png_do_dither PNGARG((png_row_info *row_info,
+ png_byte *row, png_byte *palette_lookup, png_byte *dither_lookup));
+extern void png_do_bgr PNGARG((png_row_info *row_info, png_byte *row));
+extern void png_do_pack PNGARG((png_row_info *row_info,
+ png_byte *row, png_byte bit_depth));
+extern void png_do_shift PNGARG((png_row_info *row_info, png_byte *row,
+ png_color_8 *bit_depth));
+extern void png_do_background PNGARG((png_row_info *row_info, png_byte *row,
+ png_color_16 *trans_values, png_color_16 *background,
+ png_color_16 *background_1,
+ png_byte *gamma_table, png_byte *gamma_from_1, png_byte *gamma_to_1,
+ png_uint_16 **gamma_16, png_uint_16 **gamma_16_from_1,
+ png_uint_16 **gamma_16_to_1, int gamma_shift));
+extern void png_do_gamma PNGARG((png_row_info *row_info, png_byte *row,
+ png_byte *gamma_table, png_uint_16 **gamma_16_table,
+ int gamma_shift));
+extern void png_do_expand_palette PNGARG((png_row_info *row_info,
+ png_byte *row, png_color *palette, png_byte *trans, int num_trans));
+extern void png_do_expand PNGARG((png_row_info *row_info,
+ png_byte *row, png_color_16 *trans_value));
+
+/* unpack 16 and 32 bit values from a string */
+extern png_uint_32 png_get_uint_32 PNGARG((png_byte *buf));
+extern png_uint_16 png_get_uint_16 PNGARG((png_byte *buf));
+
+/* read bytes into buf, and update png_ptr->crc */
+extern void png_crc_read PNGARG((png_struct *png_ptr, png_byte *buf,
+ png_uint_32 length));
+/* skip length bytes, and update png_ptr->crc */
+extern void png_crc_skip PNGARG((png_struct *png_ptr, png_uint_32 length));
+
+/* 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 */
+extern void png_handle_IHDR PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_PLTE PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_gAMA PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_sBIT PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_cHRM PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_tRNS PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_bKGD PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_hIST PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_pHYs PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_oFFs PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_tIME PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_tEXt PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+extern void png_handle_zTXt PNGARG((png_struct *png_ptr, png_info *info,
+ png_uint_32 length));
+
+/* handle the transformations for reading and writing */
+extern void png_do_read_transformations PNGARG((png_struct *png_ptr));
+extern void png_do_write_transformations PNGARG((png_struct *png_ptr));
+
+extern void png_init_read_transformations PNGARG((png_struct *png_ptr));
+
+
+#endif /* PNG_INTERNAL */
+
+/* do not put anything past this line */
+#endif /* _PNG_H */
diff --git a/pngchang.txt b/pngchang.txt
new file mode 100644
index 000000000..878a2f819
--- /dev/null
+++ b/pngchang.txt
@@ -0,0 +1,44 @@
+pngchange.txt - 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
+ changed pngtest.png for zlib 0.93
+ fixed error in libpng.txt and example.c
+
+
diff --git a/pngrcb.c b/pngrcb.c
new file mode 100644
index 000000000..50b430144
--- /dev/null
+++ b/pngrcb.c
@@ -0,0 +1,212 @@
+/* pngrcb.c - callbacks while reading a png file
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+void
+png_read_IHDR(png_struct *png_ptr, png_info *info,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int compression_type, int filter_type,
+ int interlace_type)
+{
+ if (!png_ptr || !info)
+ return;
+
+ info->width = width;
+ info->height = height;
+ info->bit_depth = bit_depth;
+ info->color_type = color_type;
+ info->compression_type = compression_type;
+ info->filter_type = filter_type;
+ info->interlace_type = interlace_type;
+ if (info->color_type == PNG_COLOR_TYPE_PALETTE)
+ info->channels = 1;
+ else if (info->color_type & PNG_COLOR_MASK_COLOR)
+ info->channels = 3;
+ else
+ info->channels = 1;
+ if (info->color_type & PNG_COLOR_MASK_ALPHA)
+ info->channels++;
+ info->pixel_depth = info->channels * info->bit_depth;
+ info->rowbytes = ((info->width * info->pixel_depth + 7) >> 3);
+}
+
+void
+png_read_PLTE(png_struct *png_ptr, png_info *info,
+ png_color *palette, int num)
+{
+ if (!png_ptr || !info)
+ return;
+
+ info->palette = palette;
+ info->num_palette = num;
+ info->valid |= PNG_INFO_PLTE;
+}
+
+void
+png_read_gAMA(png_struct *png_ptr, png_info *info, float gamma)
+{
+ if (!png_ptr || !info)
+ return;
+
+ info->gamma = gamma;
+ info->valid |= PNG_INFO_gAMA;
+}
+
+void
+png_read_sBIT(png_struct *png_ptr, png_info *info,
+ png_color_8 *sig_bit)
+{
+ if (!png_ptr || !info)
+ return;
+
+ memcpy(&(info->sig_bit), sig_bit, sizeof (png_color_8));
+ info->valid |= PNG_INFO_sBIT;
+}
+
+void
+png_read_cHRM(png_struct *png_ptr, png_info *info,
+ float white_x, float white_y, float red_x, float red_y,
+ float green_x, float green_y, float blue_x, float blue_y)
+{
+ if (!png_ptr || !info)
+ return;
+
+ info->x_white = white_x;
+ info->y_white = white_y;
+ info->x_red = red_x;
+ info->y_red = red_y;
+ info->x_green = green_x;
+ info->y_green = green_y;
+ info->x_blue = blue_x;
+ info->y_blue = blue_y;
+ info->valid |= PNG_INFO_cHRM;
+}
+
+void
+png_read_tRNS(png_struct *png_ptr, png_info *info,
+ png_byte *trans, int num_trans, png_color_16 *trans_values)
+{
+ if (!png_ptr || !info)
+ return;
+
+ if (trans)
+ {
+ info->trans = trans;
+ }
+ else
+ {
+ memcpy(&(info->trans_values), trans_values,
+ sizeof(png_color_16));
+ }
+ info->num_trans = num_trans;
+ info->valid |= PNG_INFO_tRNS;
+}
+
+void
+png_read_bKGD(png_struct *png_ptr, png_info *info,
+ png_color_16 *background)
+{
+ if (!png_ptr || !info)
+ return;
+
+ memcpy(&(info->background), background, sizeof(png_color_16));
+ info->valid |= PNG_INFO_bKGD;
+}
+
+void
+png_read_hIST(png_struct *png_ptr, png_info *info, png_uint_16 *hist)
+{
+ if (!png_ptr || !info)
+ return;
+
+ info->hist = hist;
+ info->valid |= PNG_INFO_hIST;
+}
+
+void
+png_read_pHYs(png_struct *png_ptr, png_info *info,
+ png_uint_32 res_x, png_uint_32 res_y, int unit_type)
+{
+ if (!png_ptr || !info)
+ return;
+
+ info->x_pixels_per_unit = res_x;
+ info->y_pixels_per_unit = res_y;
+ info->phys_unit_type = unit_type;
+ info->valid |= PNG_INFO_pHYs;
+}
+
+void
+png_read_oFFs(png_struct *png_ptr, png_info *info,
+ png_uint_32 offset_x, png_uint_32 offset_y, int unit_type)
+{
+ if (!png_ptr || !info)
+ return;
+
+ info->x_offset = offset_x;
+ info->y_offset = offset_y;
+ info->offset_unit_type = unit_type;
+ info->valid |= PNG_INFO_oFFs;
+}
+
+void
+png_read_tIME(png_struct *png_ptr, png_info *info,
+ png_time *mod_time)
+{
+ if (!png_ptr || !info)
+ return;
+
+ memcpy(&(info->mod_time), mod_time, sizeof (png_time));
+ info->valid |= PNG_INFO_tIME;
+}
+
+void
+png_read_zTXt(png_struct *png_ptr, png_info *info,
+ char *key, char *text, png_uint_32 text_len, int compression)
+{
+ if (!png_ptr || !info)
+ return;
+
+ if (info->max_text <= info->num_text)
+ {
+ if (info->text)
+ {
+ info->max_text = info->num_text + 16;
+ info->text = (png_text *)png_realloc(png_ptr,
+ info->text,
+ info->max_text * sizeof (png_text));
+ }
+ else
+ {
+ info->max_text = info->num_text + 16;
+ info->text = (png_text *)png_malloc(png_ptr,
+ info->max_text * sizeof (png_text));
+ info->num_text = 0;
+ }
+ }
+
+ info->text[info->num_text].key = key;
+ info->text[info->num_text].text = text;
+ info->text[info->num_text].text_length = text_len;
+ info->text[info->num_text].compression = compression;
+ info->num_text++;
+}
+
+void
+png_read_tEXt(png_struct *png_ptr, png_info *info,
+ char *key, char *text, png_uint_32 text_len)
+{
+ if (!png_ptr || !info)
+ return;
+
+ png_read_zTXt(png_ptr, info, key, text, text_len, -1);
+}
+
+
diff --git a/pngread.c b/pngread.c
new file mode 100644
index 000000000..e1afee660
--- /dev/null
+++ b/pngread.c
@@ -0,0 +1,642 @@
+
+/* pngread.c - read a png file
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* initialize png structure for reading, and allocate any memory needed */
+void
+png_read_init(png_struct *png_ptr)
+{
+ jmp_buf tmp_jmp;
+
+ memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+ memset(png_ptr, 0, sizeof (png_struct));
+ memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
+ png_ptr->zstream = &(png_ptr->zstream_struct);
+ png_ptr->zstream->zalloc = png_zalloc;
+ png_ptr->zstream->zfree = png_zfree;
+ png_ptr->zstream->opaque = (voidp)png_ptr;
+ inflateInit(png_ptr->zstream);
+ png_ptr->zstream->next_out = png_ptr->zbuf;
+ png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
+}
+
+/* read the information before the actual image data. */
+void
+png_read_info(png_struct *png_ptr, png_info *info)
+{
+ png_byte chunk_start[8];
+ png_uint_32 length;
+
+ png_read_data(png_ptr, chunk_start, 8);
+ if (memcmp(chunk_start, png_sig, 8))
+ png_error(png_ptr, "Not a Png File");
+
+ while (1)
+ {
+ png_uint_32 crc;
+
+ png_read_data(png_ptr, chunk_start, 8);
+ length = png_get_uint_32(chunk_start);
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, chunk_start + 4, 4);
+ if (!memcmp(chunk_start + 4, png_IHDR, 4))
+ {
+ if (png_ptr->mode != PNG_BEFORE_IHDR)
+ png_error(png_ptr, "Out of Place IHDR");
+
+ png_handle_IHDR(png_ptr, info, length);
+ png_ptr->mode = PNG_HAVE_IHDR;
+ }
+ else if (!memcmp(chunk_start + 4, png_PLTE, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR)
+ png_error(png_ptr, "Missing IHDR");
+
+ png_handle_PLTE(png_ptr, info, length);
+ png_ptr->mode = PNG_HAVE_PLTE;
+ }
+ else if (!memcmp(chunk_start + 4, png_gAMA, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR)
+ png_error(png_ptr, "Out of Place PLTE");
+
+ png_handle_gAMA(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_sBIT, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR)
+ png_error(png_ptr, "Out of Place sBIT");
+
+ png_handle_sBIT(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_cHRM, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR)
+ png_error(png_ptr, "Out of Place cHRM");
+
+ png_handle_cHRM(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_tRNS, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR &&
+ png_ptr->mode != PNG_HAVE_PLTE)
+ png_error(png_ptr, "Out of Place tRNS");
+
+ png_handle_tRNS(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_bKGD, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR &&
+ png_ptr->mode != PNG_HAVE_PLTE)
+ png_error(png_ptr, "Out of Place bKGD");
+
+ png_handle_bKGD(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_hIST, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_PLTE)
+ png_error(png_ptr, "Out of Place hIST");
+
+ png_handle_hIST(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_IDAT, 4))
+ {
+ png_ptr->idat_size = length;
+ png_ptr->mode = PNG_HAVE_IDAT;
+ break;
+ }
+ else if (!memcmp(chunk_start + 4, png_pHYs, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR &&
+ png_ptr->mode != PNG_HAVE_PLTE)
+ png_error(png_ptr, "Out of Place pHYs");
+
+ png_handle_pHYs(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_oFFs, 4))
+ {
+ if (png_ptr->mode != PNG_HAVE_IHDR &&
+ png_ptr->mode != PNG_HAVE_PLTE)
+ png_error(png_ptr, "Out of Place oFFs");
+
+ png_handle_oFFs(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_tIME, 4))
+ {
+ if (png_ptr->mode == PNG_BEFORE_IHDR ||
+ png_ptr->mode == PNG_AFTER_IEND)
+ png_error(png_ptr, "Out of Place tIME");
+
+ png_handle_tIME(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_tEXt, 4))
+ {
+ if (png_ptr->mode == PNG_BEFORE_IHDR ||
+ png_ptr->mode == PNG_AFTER_IEND)
+ png_error(png_ptr, "Out of Place tEXt");
+
+ png_handle_tEXt(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_zTXt, 4))
+ {
+ if (png_ptr->mode == PNG_BEFORE_IHDR ||
+ png_ptr->mode == PNG_AFTER_IEND)
+ png_error(png_ptr, "Out of Place zTXt");
+
+ png_handle_zTXt(png_ptr, info, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_IEND, 4))
+ {
+ png_error(png_ptr, "No Image in File");
+ }
+ else
+ {
+ if (isupper(chunk_start[4]))
+ png_error(png_ptr, "Unknown Critical Chunk");
+
+ png_crc_skip(png_ptr, length);
+ }
+ png_read_data(png_ptr, chunk_start, 4);
+ crc = png_get_uint_32(chunk_start);
+ if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
+ (png_ptr->crc & 0xffffffffL))
+ png_error(png_ptr, "Bad CRC value");
+ }
+}
+
+/* initialize palette, background, etc, after transformations
+ are set, but before any reading takes place. This allows
+ the user to obtail a gamma corrected palette, for example.
+ If the user doesn't call this, we will do it ourselves. */
+void
+png_start_read_image(png_struct *png_ptr)
+{
+ png_read_start_row(png_ptr);
+}
+
+void
+png_read_row(png_struct *png_ptr, png_byte *row, png_byte *dsp_row)
+{
+ int ret;
+
+ if (!(png_ptr->row_init))
+ png_read_start_row(png_ptr);
+
+ /* 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)
+ 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)
+ 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 && (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)
+ 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 && (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)
+ 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;
+ }
+ }
+
+ 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 buf[4];
+ png_uint_32 crc;
+
+ png_read_data(png_ptr, buf, 4);
+ crc = png_get_uint_32(buf);
+ if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
+ (png_ptr->crc & 0xffffffffL))
+ png_error(png_ptr, "Bad CRC value");
+
+ png_read_data(png_ptr, buf, 4);
+ png_ptr->idat_size = png_get_uint_32(buf);
+ png_reset_crc(png_ptr);
+
+ png_crc_read(png_ptr, buf, 4);
+ if (memcmp(buf, 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_AT_LAST_IDAT;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, "Compression Error");
+
+ } while (png_ptr->zstream->avail_out);
+
+ if (ret == Z_STREAM_END)
+ png_ptr->zlib_finished = 1;
+
+ 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);
+
+ if (png_ptr->row_buf[0])
+ png_read_filter_row(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ memcpy(png_ptr->prev_row, png_ptr->row_buf, (png_size_t)png_ptr->rowbytes + 1);
+
+ if (png_ptr->transformations)
+ png_do_read_transformations(png_ptr);
+
+ /* 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);
+
+ if (dsp_row)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ if (row)
+ png_combine_row(png_ptr, row,
+ png_pass_mask[png_ptr->pass]);
+ }
+ else
+ {
+ if (row)
+ png_combine_row(png_ptr, row, 0xff);
+ if (dsp_row)
+ png_combine_row(png_ptr, dsp_row, 0xff);
+ }
+ png_read_finish_row(png_ptr);
+}
+
+/* read a one or more rows of image data. If the image is interlaced,
+ and png_set_interlace_handling() has been called, the rows need to
+ 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_rows. 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_rows 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. */
+void
+png_read_rows(png_struct *png_ptr, png_byte **row,
+ png_byte **display_row, png_uint_32 num_rows)
+{
+ png_uint_32 i;
+ png_byte **rp;
+ png_byte **dp;
+
+ rp = row;
+ dp = display_row;
+ for (i = 0; i < num_rows; i++)
+ {
+ png_byte *rptr;
+ png_byte *dptr;
+
+ if (rp)
+ rptr = *rp;
+ else
+ rptr = NULL;
+ if (dp)
+ dptr = *dp;
+ else
+ dptr = NULL;
+ png_read_row(png_ptr, rptr, dptr);
+ if (row)
+ rp++;
+ if (display_row)
+ dp++;
+ }
+}
+
+/* read the image. If the image has an alpha channel or a transparency
+ chunk, and you have called png_handle_alpha(), you will need to
+ initialize the image to the current image that png will be overlaying.
+ Note that png_set_interlace_handling() has no effect on this call.
+ You only need to call this function once. If you desire to have
+ an image for each pass of a interlaced image, use png_read_rows() */
+void
+png_read_image(png_struct *png_ptr, png_byte **image)
+{
+ png_uint_32 i;
+ int pass, j;
+ png_byte **rp;
+
+ pass = png_set_interlace_handling(png_ptr);
+ for (j = 0; j < pass; j++)
+ {
+ rp = image;
+ for (i = 0; i < png_ptr->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_struct *png_ptr, png_info *info)
+{
+ png_byte chunk_start[8];
+ png_uint_32 length;
+ png_uint_32 crc;
+
+ png_read_data(png_ptr, chunk_start, 4);
+ crc = png_get_uint_32(chunk_start);
+ if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
+ (png_ptr->crc & 0xffffffffL))
+ png_error(png_ptr, "Bad CRC value");
+
+ do
+ {
+ png_read_data(png_ptr, chunk_start, 8);
+ length = png_get_uint_32(chunk_start);
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, chunk_start + 4, 4);
+
+ if (!memcmp(chunk_start + 4, png_IHDR, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_PLTE, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_gAMA, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_sBIT, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_cHRM, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_tRNS, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_bKGD, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_hIST, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_IDAT, 4))
+ {
+ if (length > 0 || png_ptr->mode != PNG_AT_LAST_IDAT)
+ png_error(png_ptr, "too many IDAT's found");
+ }
+ else if (!memcmp(chunk_start + 4, png_pHYs, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_oFFs, 4))
+ {
+ png_error(png_ptr, "invalid chunk after IDAT");
+ }
+ else if (!memcmp(chunk_start + 4, png_tIME, 4))
+ {
+ if (png_ptr->mode == PNG_BEFORE_IHDR ||
+ png_ptr->mode == PNG_AFTER_IEND)
+ png_error(png_ptr, "Out of Place tIME");
+
+ if (info)
+ png_handle_tIME(png_ptr, info, length);
+ else
+ png_crc_skip(png_ptr, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_tEXt, 4))
+ {
+ if (png_ptr->mode == PNG_BEFORE_IHDR ||
+ png_ptr->mode == PNG_AFTER_IEND)
+ png_error(png_ptr, "Out of Place tEXt");
+
+ if (info)
+ png_handle_tEXt(png_ptr, info, length);
+ else
+ png_crc_skip(png_ptr, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_zTXt, 4))
+ {
+ if (png_ptr->mode == PNG_BEFORE_IHDR ||
+ png_ptr->mode == PNG_AFTER_IEND)
+ png_error(png_ptr, "Out of Place zTXt");
+
+ if (info)
+ png_handle_zTXt(png_ptr, info, length);
+ else
+ png_crc_skip(png_ptr, length);
+ }
+ else if (!memcmp(chunk_start + 4, png_IEND, 4))
+ {
+ png_ptr->mode = PNG_AFTER_IEND;
+ }
+ else
+ {
+ if (isupper(chunk_start[4]))
+ png_error(png_ptr, "Unknown Critical Chunk");
+
+ png_crc_skip(png_ptr, length);
+ }
+ png_read_data(png_ptr, chunk_start, 4);
+ crc = png_get_uint_32(chunk_start);
+ if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
+ (png_ptr->crc & 0xffffffffL))
+ png_error(png_ptr, "Bad CRC value");
+ if (png_ptr->mode == PNG_AT_LAST_IDAT)
+ png_ptr->mode = PNG_AFTER_IDAT;
+ } while (png_ptr->mode != PNG_AFTER_IEND);
+}
+
+/* free all memory used by the read */
+void
+png_read_destroy(png_struct *png_ptr, png_info *info, png_info *end_info)
+{
+ int i;
+ jmp_buf tmp_jmp;
+
+ if (info)
+ {
+ if (info->palette != png_ptr->palette)
+ png_free(png_ptr, info->palette);
+ if (info->trans != png_ptr->trans)
+ png_free(png_ptr, info->trans);
+ if (info->hist != png_ptr->hist)
+ png_free(png_ptr, info->hist);
+ for (i = 0; i < info->num_text; i++)
+ {
+ png_large_free(png_ptr, info->text[i].key);
+ }
+
+ png_free(png_ptr, info->text);
+ memset(info, 0, sizeof(png_info));
+ }
+
+ if (end_info)
+ {
+ for (i = 0; i < end_info->num_text; i++)
+ {
+ png_large_free(png_ptr, end_info->text[i].key);
+ }
+
+ png_free(png_ptr, end_info->text);
+ memset(end_info, 0, sizeof(png_info));
+ }
+
+ png_large_free(png_ptr, png_ptr->zbuf);
+ png_large_free(png_ptr, png_ptr->row_buf);
+ png_large_free(png_ptr, png_ptr->prev_row);
+ png_large_free(png_ptr, png_ptr->palette_lookup);
+ png_free(png_ptr, png_ptr->dither_index);
+ png_free(png_ptr, png_ptr->gamma_table);
+ png_free(png_ptr, png_ptr->gamma_from_1);
+ png_free(png_ptr, png_ptr->gamma_to_1);
+ if (png_ptr->gamma_16_table)
+ {
+ for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_table[i]);
+ }
+ }
+ png_free(png_ptr, png_ptr->gamma_16_table);
+ if (png_ptr->gamma_16_from_1)
+ {
+ for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); 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)
+ {
+ for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
+ }
+ }
+ png_free(png_ptr, png_ptr->gamma_16_to_1);
+ png_free(png_ptr, png_ptr->trans);
+ png_free(png_ptr, png_ptr->hist);
+ if (!png_ptr->user_palette)
+ png_free(png_ptr, png_ptr->palette);
+
+ inflateEnd(png_ptr->zstream);
+
+ memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+ memset(png_ptr, 0, sizeof (png_struct));
+ memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+}
+
+
diff --git a/pngrtran.c b/pngrtran.c
new file mode 100644
index 000000000..0aa3b47fd
--- /dev/null
+++ b/pngrtran.c
@@ -0,0 +1,2774 @@
+
+/* pngrtran.c - transforms the data in a row for png readers
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* handle alpha and tRNS via a background color */
+void
+png_set_background(png_struct *png_ptr,
+ png_color_16 *background_color, int background_gamma_code,
+ int need_expand, float background_gamma)
+{
+ png_ptr->transformations |= PNG_BACKGROUND;
+ memcpy(&(png_ptr->background), background_color,
+ sizeof(png_color_16));
+ png_ptr->background_gamma = background_gamma;
+ png_ptr->background_gamma_type = background_gamma_code;
+ png_ptr->background_expand = need_expand;
+}
+
+/* strip 16 bit depth files to 8 bit depth */
+void
+png_set_strip_16(png_struct *png_ptr)
+{
+ png_ptr->transformations |= PNG_16_TO_8;
+}
+
+/* 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
+ is greater then the maximum number, the palette will be
+ modified to fit in the maximum number */
+
+typedef struct dsort_struct
+{
+ struct dsort_struct *next;
+ png_byte left;
+ png_byte right;
+} dsort;
+
+void
+png_set_dither(png_struct *png_ptr, png_color *palette,
+ int num_palette, int maximum_colors, png_uint_16 *histogram,
+ int full_dither)
+{
+ png_ptr->transformations |= PNG_DITHER;
+
+ if (!full_dither)
+ {
+ int i;
+
+ png_ptr->dither_index = png_malloc(png_ptr,
+ num_palette * sizeof (png_byte));
+ for (i = 0; i < num_palette; i++)
+ png_ptr->dither_index[i] = i;
+ }
+
+ if (num_palette > maximum_colors)
+ {
+ if (histogram)
+ {
+ /* this is easy enough, just throw out the least used colors.
+ perhaps not the best solution, but good enough */
+
+ int i;
+ png_byte *sort;
+
+ /* initialize an array to sort colors */
+ sort = (png_byte *)png_malloc(png_ptr, num_palette * sizeof (png_byte));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ sort[i] = 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;
+
+ /* put all the useful colors within the max, but don't
+ move the others */
+ j = num_palette;
+ for (i = 0; i < maximum_colors; i++)
+ {
+ if (sort[i] >= maximum_colors)
+ {
+ do
+ j--;
+ while (sort[j] >= maximum_colors);
+ palette[i] = palette[j];
+ }
+ }
+ }
+ else
+ {
+ int j;
+
+ /* move all the used colors inside the max limit, and
+ develop a translation table */
+ j = num_palette;
+ for (i = 0; i < maximum_colors; i++)
+ {
+ /* only move the colors we need to */
+ if (sort[i] >= maximum_colors)
+ {
+ png_color tmp_color;
+
+ do
+ j--;
+ while (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] = i;
+ png_ptr->dither_index[i] = j;
+ }
+ }
+ /* find closest color for those colors we are not
+ using */
+ for (i = 0; i < num_palette; i++)
+ {
+ if (png_ptr->dither_index[i] >= maximum_colors)
+ {
+ int min_d, j, min_j, index;
+
+ /* find the closest color to one we threw out */
+ index = png_ptr->dither_index[i];
+ min_d = PNG_COLOR_DIST(palette[index],
+ palette[0]);
+ min_j = 0;
+ for (j = 1; j < maximum_colors; j++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[index],
+ palette[j]);
+
+ if (d < min_d)
+ {
+ min_d = d;
+ min_j = j;
+ }
+ }
+ /* point to closest color */
+ png_ptr->dither_index[i] = min_j;
+ }
+ }
+ }
+ 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).
+ */
+ int i;
+ int max_d;
+ int num_new_palette;
+ dsort **hash;
+ png_byte *index_to_palette;
+ /* where the original index currently is in the palette */
+ png_byte *palette_to_index;
+ /* which original index points to this palette color */
+
+ /* initialize palette index arrays */
+ index_to_palette = (png_byte *)png_malloc(png_ptr,
+ num_palette * sizeof (png_byte));
+ palette_to_index = (png_byte *)png_malloc(png_ptr,
+ num_palette * sizeof (png_byte));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ {
+ index_to_palette[i] = i;
+ palette_to_index[i] = i;
+ }
+
+ hash = (dsort **)png_malloc(png_ptr, 769 * sizeof (dsort *));
+ for (i = 0; i < 769; i++)
+ hash[i] = (dsort *)0;
+/* memset(hash, 0, 769 * sizeof (dsort *)); */
+
+ 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)
+ {
+ dsort *t;
+
+ t = png_malloc(png_ptr, sizeof (dsort));
+ t->next = hash[d];
+ t->left = i;
+ t->right = j;
+ hash[d] = t;
+ }
+ }
+ }
+
+ for (i = 0; i <= max_d; i++)
+ {
+ if (hash[i])
+ {
+ dsort *p;
+
+ for (p = hash[i]; p; p = p->next)
+ {
+ if (index_to_palette[p->left] < num_new_palette &&
+ 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 (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] = num_new_palette;
+ palette_to_index[num_new_palette] = j;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ }
+
+ for (i = 0; i < 769; i++)
+ {
+ if (hash[i])
+ {
+ dsort *p;
+
+ p = hash[i];
+ while (p)
+ {
+ dsort *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))
+ {
+ png_ptr->palette = palette;
+ png_ptr->user_palette = 1;
+ }
+ png_ptr->num_palette = num_palette;
+
+ if (full_dither)
+ {
+ int i;
+ int total_bits, num_red, num_green, num_blue;
+ png_uint_32 num_entries;
+ png_byte *distance;
+
+ total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
+ PNG_DITHER_BLUE_BITS;
+
+ num_red = (1 << PNG_DITHER_RED_BITS);
+ num_green = (1 << PNG_DITHER_GREEN_BITS);
+ num_blue = (1 << PNG_DITHER_BLUE_BITS);
+ num_entries = ((png_uint_32)1 << total_bits);
+
+ png_ptr->palette_lookup = (png_byte *)png_large_malloc(png_ptr,
+ (png_size_t)num_entries * sizeof (png_byte));
+
+ memset(png_ptr->palette_lookup, 0, (png_size_t)num_entries * sizeof (png_byte));
+
+ distance = (png_byte *)png_large_malloc(png_ptr,
+ (png_size_t)num_entries * sizeof (png_byte));
+
+ memset(distance, 0xff, (png_size_t)num_entries * sizeof (png_byte));
+
+ for (i = 0; i < num_palette; i++)
+ {
+ int r, g, b, ir, ig, ib;
+
+ r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
+ g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
+ b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
+
+ for (ir = 0; ir < num_red; ir++)
+ {
+ int dr, index_r;
+
+ dr = abs(ir - r);
+ index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
+ for (ig = 0; ig < num_green; ig++)
+ {
+ int dg, dt, dm, index_g;
+
+ dg = abs(ig - g);
+ dt = dr + dg;
+ dm = ((dr > dg) ? dr : dg);
+ index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
+ for (ib = 0; ib < num_blue; ib++)
+ {
+ int index, db, dmax, d;
+
+ index = index_g | ib;
+ db = abs(ib - b);
+ dmax = ((dm > db) ? dm : db);
+ d = dmax + dt + db;
+
+ if (d < distance[index])
+ {
+ distance[index] = d;
+ png_ptr->palette_lookup[index] = i;
+ }
+ }
+ }
+ }
+ }
+
+ png_large_free(png_ptr, distance);
+ }
+#ifdef oldway
+ d = TABLE_COLOR_DISTANCE(index, palette[i]);
+ dt = TABLE_DISTANCE(index);
+ if (d < dt)
+ png_ptr->palette_lookup[index] = i;
+
+ for (ir = r + 1, index2 = index; ir < num_red; ir++)
+ {
+ index2 += (1 << (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS));
+ d = RGB_COLOR_DISTANCE(r, g, b, palette[i]);
+ dt = TABLE_DISTANCE(index2);
+ if (d < dt)
+ png_ptr->palette_lookup[index2] = i;
+ else
+ break;
+ }
+
+
+
+ i = 0;
+ for (ir = 0; ir < num_red; ir++)
+ {
+ r = (ir * 255) / (num_red - 1);
+ for (ig = 0; ig < num_green; ig++)
+ {
+ g = (ig * 255) / (num_green - 1);
+ for (ib = 0; ib < num_blue; ib++)
+ {
+ int min_d, j, k, d;
+
+ b = (ib * 255) / (num_blue - 1);
+ min_d = 1024;
+ k = 0;
+ for (j = 0; j < png_ptr->num_palette; j++)
+ {
+ d = abs(r - (int)png_ptr->palette[j].red) +
+ abs(g - (int)png_ptr->palette[j].green) +
+ abs(b - (int)png_ptr->palette[j].blue);
+ if (d < min_d)
+ {
+ min_d = d;
+ k = j;
+ }
+ }
+ png_ptr->palette_lookup[i++] = k;
+ }
+ }
+ }
+#endif
+}
+
+/* transform the image from the file_gamma to the screen_gamma */
+void
+png_set_gamma(png_struct *png_ptr, float screen_gamma,
+ float file_gamma)
+{
+ png_ptr->transformations |= PNG_GAMMA;
+ png_ptr->gamma = file_gamma;
+ png_ptr->display_gamma = screen_gamma;
+}
+
+/* expand paletted images to rgb, expand grayscale images of
+ less then 8 bit depth to 8 bit depth, and expand tRNS chunks
+ to alpha channels */
+void
+png_set_expand(png_struct *png_ptr)
+{
+ png_ptr->transformations |= PNG_EXPAND;
+}
+
+void
+png_set_gray_to_rgb(png_struct *png_ptr)
+{
+ png_ptr->transformations |= PNG_GRAY_TO_RGB;
+}
+
+/* initialize everything needed for the read. This includes modifying
+ the palette */
+void
+png_init_read_transformations(png_struct *png_ptr)
+{
+ int color_type;
+
+ color_type = png_ptr->color_type;
+
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (color_type == PNG_COLOR_TYPE_GRAY &&
+ png_ptr->bit_depth < 8 &&
+ (!(png_ptr->transformations & PNG_BACKGROUND) ||
+ png_ptr->background_expand))
+ {
+ /* expand background chunk. While this may not be
+ the fastest way to do this, it only happens once
+ per file. */
+ switch (png_ptr->bit_depth)
+ {
+ case 1:
+ png_ptr->background.gray *= 0xff;
+ break;
+ case 2:
+ png_ptr->background.gray *= 0x55;
+ break;
+ case 4:
+ png_ptr->background.gray *= 0x11;
+ break;
+ }
+ }
+ if (color_type == PNG_COLOR_TYPE_PALETTE &&
+ (png_ptr->transformations & PNG_BACKGROUND) &&
+ png_ptr->background_expand)
+ {
+ /* expand background chunk */
+ 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;
+ color_type = PNG_COLOR_TYPE_RGB;
+ }
+ }
+
+ png_ptr->background_1 = png_ptr->background;
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+ png_build_gamma_table(png_ptr);
+ if ((png_ptr->transformations & PNG_BACKGROUND) &&
+ (color_type != PNG_COLOR_TYPE_PALETTE))
+ {
+ if (png_ptr->background_gamma_type != PNG_BACKGROUND_GAMMA_UNKNOWN)
+ {
+ double g, gs, m;
+
+ m = (double)((png_uint_32)1 << png_ptr->bit_depth);
+ g = 1.0;
+ gs = 1.0;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->display_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->display_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->display_gamma);
+ break;
+ }
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ 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
+ {
+ 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);
+ }
+ }
+ }
+ }
+}
+
+/* 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_struct *png_ptr)
+{
+ if ((png_ptr->transformations & PNG_EXPAND) &&
+ 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->transformations & PNG_EXPAND)
+ {
+ 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);
+ }
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ 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);
+ else if (png_ptr->transformations & PNG_GAMMA)
+ 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);
+ if (png_ptr->transformations & PNG_16_TO_8)
+ png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_DITHER)
+ png_do_dither(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette_lookup, png_ptr->dither_index);
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_RGBA)
+ png_do_read_rgbx(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_XRGB)
+ png_do_read_xrgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+}
+
+/* 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_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = 7 - (int)((row_info->width + 7) & 7);
+ for (i = 0; i < row_info->width; i++)
+ {
+ *dp = (*sp >> shift) & 0x1;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
+ for (i = 0; i < row_info->width; i++)
+ {
+ *dp = (*sp >> shift) & 0x3;
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((1 - ((row_info->width + 1) & 1)) << 4);
+ for (i = 0; i < row_info->width; i++)
+ {
+ *dp = (*sp >> shift) & 0xf;
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8 * row_info->channels;
+ row_info->rowbytes = row_info->width * row_info->channels;
+ }
+}
+
+/* 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_info *row_info, png_byte *row,
+ png_color_8 *sig_bits)
+{
+ if (row && row_info && sig_bits)
+ {
+ int shift[4];
+ int channels;
+
+ channels = 0;
+ 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;
+ }
+
+ switch (row_info->bit_depth)
+ {
+ case 2:
+ {
+ png_byte *bp;
+ png_uint_32 i;
+
+ for (bp = row, i = 0;
+ i < row_info->rowbytes;
+ i++, bp++)
+ {
+ *bp >>= 1;
+ *bp &= 0x55;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_byte *bp, mask;
+ png_uint_32 i;
+
+ mask = (png_byte)(((int)0xf0 >> shift[0]) & (int)0xf0) |
+ ((int)0xf >> shift[0]);
+ for (bp = row, i = 0;
+ i < row_info->rowbytes;
+ i++, bp++)
+ {
+ *bp >>= shift[0];
+ *bp &= mask;
+ }
+ break;
+ }
+ case 8:
+ {
+ png_byte *bp;
+ png_uint_32 i;
+
+ for (bp = row, i = 0;
+ i < row_info->width; i++)
+ {
+ int c;
+
+ for (c = 0; c < row_info->channels; c++, bp++)
+ {
+ *bp >>= shift[c];
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+ png_byte *bp;
+ png_uint_16 value;
+ png_uint_32 i;
+
+ for (bp = row, i = 0;
+ i < row_info->width; i++)
+ {
+ int c;
+
+ for (c = 0; c < row_info->channels; c++, bp += 2)
+ {
+ value = (*bp << 8) + *(bp + 1);
+ value >>= shift[c];
+ *bp = value >> 8;
+ *(bp + 1) = value & 0xff;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* chop rows of bit depth 16 down to 8 */
+void
+png_do_chop(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->bit_depth == 16)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row + 2;
+ dp = row + 1;
+ for (i = 1; i < row_info->width * row_info->channels; i++)
+ {
+ *dp = *sp;
+ sp += 2;
+ dp++;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8 * row_info->channels;
+ row_info->rowbytes = row_info->width * row_info->channels;
+ }
+}
+
+/* add filler byte after rgb */
+void
+png_do_read_rgbx(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->color_type == 2 &&
+ row_info->bit_depth == 8)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 1, sp = row + (png_size_t)row_info->width * 3,
+ dp = row + (png_size_t)row_info->width * 4;
+ i < row_info->width;
+ i++)
+ {
+ *(--dp) = 0xff;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = 0xff;
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_info->width * 4;
+ }
+}
+
+/* add filler byte before rgb */
+void
+png_do_read_xrgb(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->color_type == 2 &&
+ row_info->bit_depth == 8)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row + (png_size_t)row_info->width * 3,
+ dp = row + (png_size_t)row_info->width * 4;
+ i < row_info->width;
+ i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = 0xff;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_info->width * 4;
+ }
+}
+
+/* expand grayscale files to rgb, with or without alpha */
+void
+png_do_gray_to_rgb(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->bit_depth >= 8 &&
+ !(row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row + (png_size_t)row_info->width - 1,
+ dp = row + (png_size_t)row_info->width * 3 - 1;
+ i < row_info->width;
+ i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ sp--;
+ }
+ }
+ else
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row + (png_size_t)row_info->width * 2 - 1,
+ dp = row + (png_size_t)row_info->width * 6 - 1;
+ i < row_info->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_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row + (png_size_t)row_info->width * 2 - 1,
+ dp = row + (png_size_t)row_info->width * 4 - 1;
+ i < row_info->width;
+ i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ sp--;
+ }
+ }
+ else
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row + (png_size_t)row_info->width * 4 - 1,
+ dp = row + (png_size_t)row_info->width * 8 - 1;
+ i < row_info->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 += 2;
+ row_info->color_type |= PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = row_info->channels * row_info->bit_depth;
+ row_info->rowbytes = ((row_info->width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+}
+
+/* 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_color *palette)
+{
+ int num_palette;
+ int color_inc;
+ int i;
+ int v;
+
+ if (!palette)
+ 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;
+ break;
+ }
+
+ for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
+ {
+ palette[i].red = v;
+ palette[i].green = v;
+ palette[i].blue = v;
+ }
+}
+
+void
+png_correct_palette(png_struct *png_ptr, png_color *palette,
+ int num_palette)
+{
+ if ((png_ptr->transformations & (PNG_GAMMA)) &&
+ (png_ptr->transformations & (PNG_BACKGROUND)))
+ {
+ if (png_ptr->color_type == 3)
+ {
+ int i;
+ png_color back, back_1;
+
+ back.red = png_ptr->gamma_table[png_ptr->palette[
+ png_ptr->background.index].red];
+ back.green = png_ptr->gamma_table[png_ptr->palette[
+ png_ptr->background.index].green];
+ back.blue = png_ptr->gamma_table[png_ptr->palette[
+ png_ptr->background.index].blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->palette[
+ png_ptr->background.index].red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->palette[
+ png_ptr->background.index].green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->palette[
+ png_ptr->background.index].blue];
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i < (int)png_ptr->num_trans &&
+ png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (i < (int)png_ptr->num_trans &&
+ png_ptr->trans[i] != 0xff)
+ {
+ int v;
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
+ v = (int)(((png_uint_32)(v) *
+ (png_uint_32)(png_ptr->trans[i]) +
+ (png_uint_32)(back_1.red) *
+ (png_uint_32)(255 - png_ptr->trans[i]) +
+ 127) / 255);
+ palette[i].red = png_ptr->gamma_from_1[v];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
+ v = (int)(((png_uint_32)(v) *
+ (png_uint_32)(png_ptr->trans[i]) +
+ (png_uint_32)(back_1.green) *
+ (png_uint_32)(255 - png_ptr->trans[i]) +
+ 127) / 255);
+ palette[i].green = png_ptr->gamma_from_1[v];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
+ v = (int)(((png_uint_32)(v) *
+ (png_uint_32)(png_ptr->trans[i]) +
+ (png_uint_32)(back_1.blue) *
+ (png_uint_32)(255 - png_ptr->trans[i]) +
+ 127) / 255);
+ palette[i].blue = png_ptr->gamma_from_1[v];
+ }
+ 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, back;
+
+ back = png_ptr->gamma_table[png_ptr->background.gray];
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (palette[i].red == png_ptr->trans_values.gray)
+ {
+ palette[i].red = back;
+ palette[i].green = back;
+ palette[i].blue = 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 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];
+ }
+ }
+ else if (png_ptr->transformations & (PNG_BACKGROUND))
+ {
+ if (png_ptr->color_type == 3)
+ {
+ int i;
+ png_byte br, bg, bb;
+
+ br = palette[png_ptr->background.index].red;
+ bg = palette[png_ptr->background.index].green;
+ bb = palette[png_ptr->background.index].blue;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i >= (int)png_ptr->num_trans ||
+ png_ptr->trans[i] == 0)
+ {
+ palette[i].red = br;
+ palette[i].green = bg;
+ palette[i].blue = bb;
+ }
+ else if (i < (int)png_ptr->num_trans ||
+ png_ptr->trans[i] != 0xff)
+ {
+ palette[i].red = (png_byte)((
+ (png_uint_32)(png_ptr->palette[i].red) *
+ (png_uint_32)(png_ptr->trans[i]) +
+ (png_uint_32)(br) *
+ (png_uint_32)(255 - png_ptr->trans[i]) +
+ 127) / 255);
+ palette[i].green = (png_byte)((
+ (png_uint_32)(png_ptr->palette[i].green) *
+ (png_uint_32)(png_ptr->trans[i]) +
+ (png_uint_32)(bg) *
+ (png_uint_32)(255 - png_ptr->trans[i]) +
+ 127) / 255);
+ palette[i].blue = (png_byte)((
+ (png_uint_32)(png_ptr->palette[i].blue) *
+ (png_uint_32)(png_ptr->trans[i]) +
+ (png_uint_32)(bb) *
+ (png_uint_32)(255 - png_ptr->trans[i]) +
+ 127) / 255);
+ }
+ }
+ }
+ else /* assume grayscale palette (what else could it be?) */
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i == (int)png_ptr->trans_values.gray)
+ {
+ palette[i].red = (png_byte)png_ptr->background.gray;
+ palette[i].green = (png_byte)png_ptr->background.gray;
+ palette[i].blue = (png_byte)png_ptr->background.gray;
+ }
+ }
+ }
+ }
+}
+
+/* replace any alpha or transparency with the supplied background color.
+ background is the color (in rgb or grey or palette index, as
+ appropriate). note that paletted files are taken care of elsewhere */
+void
+png_do_background(png_row_info *row_info, png_byte *row,
+ png_color_16 *trans_values, png_color_16 *background,
+ png_color_16 *background_1,
+ png_byte *gamma_table, png_byte *gamma_from_1, png_byte *gamma_to_1,
+ png_uint_16 **gamma_16, png_uint_16 **gamma_16_from_1,
+ png_uint_16 **gamma_16_to_1, int gamma_shift)
+{
+ if (row && row_info && background &&
+ (!(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:
+ {
+ png_byte *sp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row;
+ shift = 7;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((*sp >> shift) & 0x1) ==
+ trans_values->gray)
+ {
+ *sp &= ((0x7f7f >> (7 - shift)) & 0xff);
+ *sp |= (background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 7;
+ sp++;
+ }
+ else
+ shift--;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((*sp >> shift) & 0x3) ==
+ trans_values->gray)
+ {
+ *sp &= ((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row + 1;
+ shift = 4;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((*sp >> shift) & 0xf) ==
+ trans_values->gray)
+ {
+ *sp &= ((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ break;
+ }
+ case 8:
+ {
+ if (gamma_table)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = background->gray;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = background->gray;
+ }
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+ if (gamma_16)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = ((png_uint_16)(*sp) << 8) +
+ (png_uint_16)(*(sp + 1));
+ if (v == trans_values->gray)
+ {
+ *sp = (background->gray >> 8) & 0xff;
+ *(sp + 1) = background->gray & 0xff;
+ }
+ else
+ {
+ v = gamma_16[
+ *(sp + 1) >> gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = ((png_uint_16)(*sp) << 8) +
+ (png_uint_16)(*(sp + 1));
+ if (v == trans_values->gray)
+ {
+ *sp = (background->gray >> 8) & 0xff;
+ *(sp + 1) = background->gray & 0xff;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ if (gamma_table)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = background->red;
+ *(sp + 1) = background->green;
+ *(sp + 2) = background->blue;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ *(sp + 1) = gamma_table[*(sp + 1)];
+ *(sp + 2) = gamma_table[*(sp + 2)];
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = background->red;
+ *(sp + 1) = background->green;
+ *(sp + 2) = background->blue;
+ }
+ }
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ if (gamma_16)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp += 6)
+ {
+ png_uint_16 r, g, b;
+
+ r = ((png_uint_16)(*sp) << 8) +
+ (png_uint_16)(*(sp + 1));
+ g = ((png_uint_16)(*(sp + 2)) << 8) +
+ (png_uint_16)(*(sp + 3));
+ b = ((png_uint_16)(*(sp + 4)) << 8) +
+ (png_uint_16)(*(sp + 5));
+ if (r == trans_values->red &&
+ g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ *sp = (background->red >> 8) & 0xff;
+ *(sp + 1) = background->red & 0xff;
+ *(sp + 2) = (background->green >> 8) & 0xff;
+ *(sp + 3) = background->green & 0xff;
+ *(sp + 4) = (background->blue >> 8) & 0xff;
+ *(sp + 5) = background->blue & 0xff;
+ }
+ else
+ {
+ png_uint_16 v;
+ v = gamma_16[
+ *(sp + 1) >> gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ v = gamma_16[
+ *(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(sp + 2) = (v >> 8) & 0xff;
+ *(sp + 3) = v & 0xff;
+ v = gamma_16[
+ *(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(sp + 4) = (v >> 8) & 0xff;
+ *(sp + 5) = v & 0xff;
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++, sp += 6)
+ {
+ png_uint_16 r, g, b;
+
+ r = ((png_uint_16)(*sp) << 8) +
+ (png_uint_16)(*(sp + 1));
+ g = ((png_uint_16)(*(sp + 2)) << 8) +
+ (png_uint_16)(*(sp + 3));
+ b = ((png_uint_16)(*(sp + 4)) << 8) +
+ (png_uint_16)(*(sp + 5));
+ if (r == trans_values->red &&
+ g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ *sp = (background->red >> 8) & 0xff;
+ *(sp + 1) = background->red & 0xff;
+ *(sp + 2) = (background->green >> 8) & 0xff;
+ *(sp + 3) = background->green & 0xff;
+ *(sp + 4) = (background->blue >> 8) & 0xff;
+ *(sp + 5) = background->blue & 0xff;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ switch (row_info->bit_depth)
+ {
+ case 8:
+ {
+ if (gamma_to_1 && gamma_from_1 && gamma_table)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 2, dp++)
+ {
+ png_uint_16 a;
+
+ a = *(sp + 1);
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ }
+ else if (a == 0)
+ {
+ *dp = background->gray;
+ }
+ else
+ {
+ png_uint_16 v;
+
+ v = gamma_to_1[*sp];
+ v = ((png_uint_16)(v) * a +
+ (png_uint_16)background_1->gray *
+ (255 - a) + 127) / 255;
+ *dp = gamma_from_1[v];
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 2, dp++)
+ {
+ png_uint_16 a;
+
+ a = *(sp + 1);
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ }
+ else if (a == 0)
+ {
+ *dp = background->gray;
+ }
+ else
+ {
+ *dp = ((png_uint_16)(*sp) * a +
+ (png_uint_16)background_1->gray *
+ (255 - a) + 127) / 255;
+ }
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+ if (gamma_16 && gamma_16_from_1 && gamma_16_to_1)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a;
+
+ a = ((png_uint_16)(*(sp + 2)) << 8) +
+ (png_uint_16)(*(sp + 3));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_32 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)
+ {
+ *dp = (background->gray >> 8) & 0xff;
+ *(dp + 1) = background->gray & 0xff;
+ }
+ else
+ {
+ png_uint_32 g, v;
+
+ g = gamma_16_to_1[
+ *(sp + 1) >> gamma_shift][*sp];
+ v = (g * (png_uint_32)a +
+ (png_uint_32)background_1->gray *
+ (png_uint_32)((png_uint_16)65535 - a) +
+ (png_uint_16)32767) / (png_uint_16)65535;
+ v = gamma_16_from_1[(size_t)(
+ (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a;
+
+ a = ((png_uint_16)(*(sp + 2)) << 8) +
+ (png_uint_16)(*(sp + 3));
+ if (a == (png_uint_16)0xffff)
+ {
+ memcpy(dp, sp, 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (background->gray >> 8) & 0xff;
+ *(dp + 1) = background->gray & 0xff;
+ }
+ else
+ {
+ png_uint_32 g, v;
+
+ g = ((png_uint_32)(*sp) << 8) +
+ (png_uint_32)(*(sp + 1));
+ v = (g * (png_uint_32)a +
+ (png_uint_32)background_1->gray *
+ (png_uint_32)((png_uint_16)65535 - a) +
+ (png_uint_16)32767) / (png_uint_16)65535;
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ if (gamma_to_1 && gamma_from_1 && gamma_table)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 4, dp += 3)
+ {
+ png_uint_16 a;
+
+ 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)
+ {
+ *dp = background->red;
+ *(dp + 1) = background->green;
+ *(dp + 2) = background->blue;
+ }
+ else
+ {
+ png_uint_16 v;
+
+ v = gamma_to_1[*sp];
+ v = ((png_uint_16)(v) * a +
+ (png_uint_16)background_1->red *
+ (255 - a) + 127) / 255;
+ *dp = gamma_from_1[v];
+ v = gamma_to_1[*(sp + 1)];
+ v = ((png_uint_16)(v) * a +
+ (png_uint_16)background_1->green *
+ (255 - a) + 127) / 255;
+ *(dp + 1) = gamma_from_1[v];
+ v = gamma_to_1[*(sp + 2)];
+ v = ((png_uint_16)(v) * a +
+ (png_uint_16)background_1->blue *
+ (255 - a) + 127) / 255;
+ *(dp + 2) = gamma_from_1[v];
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 4, dp += 3)
+ {
+ png_uint_16 a;
+
+ a = *(sp + 3);
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ *(dp + 1) = *(sp + 1);
+ *(dp + 2) = *(sp + 2);
+ }
+ else if (a == 0)
+ {
+ *dp = background->red;
+ *(dp + 1) = background->green;
+ *(dp + 2) = background->blue;
+ }
+ else
+ {
+ *dp = ((png_uint_16)(*sp) * a +
+ (png_uint_16)background->red *
+ (255 - a) + 127) / 255;
+ *(dp + 1) = ((png_uint_16)(*(sp + 1)) * a +
+ (png_uint_16)background->green *
+ (255 - a) + 127) / 255;
+ *(dp + 2) = ((png_uint_16)(*(sp + 2)) * a +
+ (png_uint_16)background->blue *
+ (255 - a) + 127) / 255;
+ }
+ }
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ if (gamma_16 && gamma_16_from_1 && gamma_16_to_1)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a;
+
+ a = ((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 = (v >> 8) & 0xff;
+ *(dp + 1) = v & 0xff;
+ v = gamma_16[
+ *(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(dp + 2) = (v >> 8) & 0xff;
+ *(dp + 3) = v & 0xff;
+ v = gamma_16[
+ *(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(dp + 4) = (v >> 8) & 0xff;
+ *(dp + 5) = v & 0xff;
+ }
+ else if (a == 0)
+ {
+ *dp = (background->red >> 8) & 0xff;
+ *(dp + 1) = background->red & 0xff;
+ *(dp + 2) = (background->green >> 8) & 0xff;
+ *(dp + 3) = background->green & 0xff;
+ *(dp + 4) = (background->blue >> 8) & 0xff;
+ *(dp + 5) = background->blue & 0xff;
+ }
+ else
+ {
+ png_uint_32 v;
+
+ v = gamma_16_to_1[
+ *(sp + 1) >> gamma_shift][*sp];
+ v = (v * (png_uint_32)a +
+ (png_uint_32)background->red *
+ (png_uint_32)((png_uint_16)65535 - a) +
+ (png_uint_16)32767) / (png_uint_16)65535;
+ v = gamma_16_from_1[(size_t)(
+ (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16_to_1[
+ *(sp + 3) >> gamma_shift][*(sp + 2)];
+ v = (v * (png_uint_32)a +
+ (png_uint_32)background->green *
+ (png_uint_32)((png_uint_16)65535 - a) +
+ (png_uint_16)32767) / (png_uint_16)65535;
+ v = gamma_16_from_1[(size_t)(
+ (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16_to_1[
+ *(sp + 5) >> gamma_shift][*(sp + 4)];
+ v = (v * (png_uint_32)a +
+ (png_uint_32)background->blue *
+ (png_uint_32)((png_uint_16)65535 - a) +
+ (png_uint_16)32767) / (png_uint_16)65535;
+ v = gamma_16_from_1[(size_t)(
+ (v & 0xff) >> gamma_shift)][(size_t)(v >> 8)];
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row,
+ dp = row;
+ i < row_info->width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a;
+
+ a = ((png_uint_16)(*(sp + 6)) << 8) +
+ (png_uint_16)(*(sp + 7));
+ if (a == (png_uint_16)0xffff)
+ {
+ memcpy(dp, sp, 6);
+ }
+ else if (a == 0)
+ {
+ *dp = (background->red >> 8) & 0xff;
+ *(dp + 1) = background->red & 0xff;
+ *(dp + 2) = (background->green >> 8) & 0xff;
+ *(dp + 3) = background->green & 0xff;
+ *(dp + 4) = (background->blue >> 8) & 0xff;
+ *(dp + 5) = background->blue & 0xff;
+ }
+ else
+ {
+ png_uint_32 r, g, b, v;
+
+ r = ((png_uint_32)(*sp) << 8) +
+ (png_uint_32)(*(sp + 1));
+ g = ((png_uint_32)(*(sp + 2)) << 8) +
+ (png_uint_32)(*(sp + 3));
+ b = ((png_uint_32)(*(sp + 4)) << 8) +
+ (png_uint_32)(*(sp + 5));
+ v = (r * (png_uint_32)a +
+ (png_uint_32)background->red *
+ (png_uint_32)((png_uint_32)65535 - a) +
+ (png_uint_32)32767) / (png_uint_32)65535;
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ v = (g * (png_uint_32)a +
+ (png_uint_32)background->green *
+ (png_uint_32)((png_uint_32)65535 - a) +
+ (png_uint_32)32767) / (png_uint_32)65535;
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ v = (b * (png_uint_32)a +
+ (png_uint_32)background->blue *
+ (png_uint_32)((png_uint_32)65535 - a) +
+ (png_uint_32)32767) / (png_uint_32)65535;
+ *(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 -= 1;
+ row_info->pixel_depth = row_info->channels *
+ row_info->bit_depth;
+ row_info->rowbytes = ((row_info->width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+ }
+}
+
+/* gamma correct the image, avoiding the alpha channel. Make sure
+ you do this after you deal with the trasparency 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(). If your bit depth < 8, gamma correct a
+ palette, not the data. */
+void
+png_do_gamma(png_row_info *row_info, png_byte *row,
+ png_byte *gamma_table, png_uint_16 **gamma_16_table,
+ int gamma_shift)
+{
+ if (row && row_info && ((row_info->bit_depth <= 8 && gamma_table) ||
+ (row_info->bit_depth == 16 && gamma_16_table)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 2;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->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)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row;
+ i < row_info->width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >>
+ gamma_shift][*sp];
+ *sp = (v >> 8) & 0xff;
+ *(sp + 1) = v & 0xff;
+ sp += 2;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* 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_info *row_info, png_byte *row,
+ png_color *palette,
+ png_byte *trans, int num_trans)
+{
+ if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = 7 - (int)((row_info->width + 7) & 7);
+ for (i = 0; i < row_info->width; i++)
+ {
+ if ((*sp >> shift) & 0x1)
+ *dp = 1;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift, value;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp = value;
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift, value;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((row_info->width & 1) << 2);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp = 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_info->width;
+ }
+ switch (row_info->bit_depth)
+ {
+ case 8:
+ {
+ if (trans)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)row_info->width - 1;
+ dp = row + (png_size_t)(row_info->width << 2) - 1;
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (*sp >= (png_byte)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_info->width * 4;
+ row_info->color_type = 6;
+ row_info->channels = 4;
+ }
+ else
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)row_info->width - 1;
+ dp = row + (png_size_t)(row_info->width * 3) - 1;
+
+ for (i = 0; i < row_info->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_info->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_info *row_info, png_byte *row,
+ png_color_16 *trans_value)
+{
+ if (row && row_info)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY &&
+ row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = 7 - (int)((row_info->width + 7) & 7);
+ for (i = 0; i < row_info->width; i++)
+ {
+ if ((*sp >> shift) & 0x1)
+ *dp = 0xff;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift, value;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp = (value | (value << 2) | (value << 4) |
+ (value << 6));
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift, value;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)row_info->width - 1;
+ shift = (int)((1 - ((row_info->width + 1) & 1)) << 2);
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp = (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_info->width;
+ }
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY && trans_value)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)row_info->width - 1;
+ dp = row + (png_size_t)(row_info->width << 1) - 1;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (*sp == trans_value->gray)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_info->rowbytes << 1) - 1;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (((png_uint_16)*(sp) |
+ ((png_uint_16)*(sp - 1) << 8)) == trans_value->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 = (row_info->bit_depth << 1);
+ row_info->rowbytes =
+ ((row_info->width * row_info->pixel_depth) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_info->width << 2) - 1;
+ for (i = 0; i < row_info->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)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_info->width << 3) - 1;
+ for (i = 0; i < row_info->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 = (row_info->bit_depth << 2);
+ row_info->rowbytes =
+ ((row_info->width * row_info->pixel_depth) >> 3);
+ }
+ }
+}
+
+void
+png_do_dither(png_row_info *row_info, png_byte *row,
+ png_byte *palette_lookup, png_byte *dither_lookup)
+{
+ if (row && row_info)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ palette_lookup && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_info->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_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
+ palette_lookup && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_info->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_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+ dither_lookup && row_info->bit_depth == 8)
+ {
+ png_byte *sp;
+ png_uint_32 i;
+
+ sp = row;
+ for (i = 0; i < row_info->width; i++, sp++)
+ {
+ *sp = dither_lookup[*sp];
+ }
+ }
+ }
+}
+
+static int png_gamma_shift[] =
+ {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
+
+void
+png_build_gamma_table(png_struct *png_ptr)
+{
+ if (png_ptr->bit_depth <= 8)
+ {
+ int i;
+ double g;
+
+ g = 1.0 / (png_ptr->gamma * png_ptr->display_gamma);
+
+ png_ptr->gamma_table = (png_byte *)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 (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_to_1 = (png_byte *)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);
+ }
+
+ g = 1.0 / (png_ptr->display_gamma);
+
+ png_ptr->gamma_from_1 = (png_byte *)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+ }
+ }
+ 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 = shift;
+
+ num = (1 << (8 - shift));
+
+ g = 1.0 / (png_ptr->gamma * png_ptr->display_gamma);
+
+ png_ptr->gamma_16_table = (png_uint_16 **)png_malloc(png_ptr,
+ num * sizeof (png_uint_16 *));
+
+ if ((png_ptr->transformations & PNG_16_TO_8) &&
+ !(png_ptr->transformations & PNG_BACKGROUND))
+ {
+ double fin, fout;
+ png_uint_32 last, max;
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16 *)png_malloc(png_ptr,
+ 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)(num << 8));
+ while (last <= max)
+ {
+ png_ptr->gamma_16_table[(int)(last >> 8)]
+ [(int)(last & 0xff)] =
+ (png_uint_16)i | ((png_uint_16)i << 8);
+ last++;
+ }
+ }
+ while (last < (num << 8))
+ {
+ png_ptr->gamma_16_table[(int)(last >> 8)][(int)(last & 0xff)] =
+ (png_uint_16)65535;
+ last++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16 *)png_malloc(png_ptr,
+ 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 (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_16_to_1 = (png_uint_16 **)png_malloc(png_ptr,
+ num * sizeof (png_uint_16 *));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_to_1[i] = (png_uint_16 *)png_malloc(png_ptr,
+ 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);
+ }
+ }
+ g = 1.0 / (png_ptr->display_gamma);
+
+ png_ptr->gamma_16_from_1 = (png_uint_16 **)png_malloc(png_ptr,
+ num * sizeof (png_uint_16 *));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_from_1[i] = (png_uint_16 *)png_malloc(png_ptr,
+ 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);
+ }
+ }
+ }
+ }
+}
diff --git a/pngrutil.c b/pngrutil.c
new file mode 100644
index 000000000..83a2973d4
--- /dev/null
+++ b/pngrutil.c
@@ -0,0 +1,1243 @@
+
+/* pngrutil.c - utilities to read a png file
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* grab an uint 32 from a buffer */
+png_uint_32
+png_get_uint_32(png_byte *buf)
+{
+ png_uint_32 i;
+
+ 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;
+}
+
+/* grab an uint 16 from a buffer */
+png_uint_16
+png_get_uint_16(png_byte *buf)
+{
+ png_uint_16 i;
+
+ i = ((png_uint_16)(*buf) << 8) +
+ (png_uint_16)(*(buf + 1));
+
+ return i;
+}
+
+/* read data, and run it through the crc */
+void
+png_crc_read(png_struct *png_ptr, png_byte *buf, png_uint_32 length)
+{
+ png_read_data(png_ptr, buf, length);
+ png_calculate_crc(png_ptr, buf, length);
+}
+
+/* skip data, but calcuate the crc anyway */
+void
+png_crc_skip(png_struct *png_ptr, png_uint_32 length)
+{
+ png_uint_32 i;
+
+ for (i = length; i > png_ptr->zbuf_size; i -= png_ptr->zbuf_size)
+ {
+ png_read_data(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_calculate_crc(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ }
+ if (i)
+ {
+ png_read_data(png_ptr, png_ptr->zbuf, i);
+ png_calculate_crc(png_ptr, png_ptr->zbuf, i);
+ }
+}
+
+/* read and check the IDHR chunk */
+void
+png_handle_IHDR(png_struct *png_ptr, png_info *info, 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;
+
+ /* check the length */
+ if (length != 13)
+ png_error(png_ptr, "Invalid IHDR chunk");
+
+ png_crc_read(png_ptr, buf, 13);
+
+ 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 || height == 0)
+ png_error(png_ptr, "Invalid Width or Height Found");
+
+ /* 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 Found");
+
+ if (color_type < 0 || color_type == 1 ||
+ color_type == 5 || color_type > 6)
+ png_error(png_ptr, "Invalid Color Type Found");
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE &&
+ bit_depth == 16)
+ png_error(png_ptr, "Found Invalid Color Type and Bit Depth Combination");
+
+ if ((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, "Found Invalid Color Type and Bit Depth Combination");
+
+ if (interlace_type > 1)
+ png_error(png_ptr, "Found Invalid Interlace Value");
+
+ if (compression_type > 0)
+ png_error(png_ptr, "Found Invalid Compression Value");
+
+ if (filter_type > 0)
+ png_error(png_ptr, "Found Invalid Filter Value");
+
+ /* set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+ png_ptr->bit_depth = bit_depth;
+ png_ptr->interlaced = interlace_type;
+ png_ptr->color_type = color_type;
+
+ /* find number of channels */
+ switch (png_ptr->color_type)
+ {
+ case 0:
+ case 3:
+ png_ptr->channels = 1;
+ break;
+ case 2:
+ png_ptr->channels = 3;
+ break;
+ case 4:
+ png_ptr->channels = 2;
+ break;
+ case 6:
+ png_ptr->channels = 4;
+ break;
+ }
+ /* set up other useful info */
+ png_ptr->pixel_depth = png_ptr->bit_depth *
+ png_ptr->channels;
+ png_ptr->rowbytes = ((png_ptr->width *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
+ /* call the IHDR callback (which should just set up info) */
+ png_read_IHDR(png_ptr, info, width, height, bit_depth,
+ color_type, compression_type, filter_type, interlace_type);
+}
+
+/* read and check the palette */
+void
+png_handle_PLTE(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ int num, i;
+ png_color *palette;
+
+ if (length % 3)
+ png_error(png_ptr, "Invalid Palette Chunk");
+
+ num = (int)length / 3;
+ palette = (png_color *)png_malloc(png_ptr, num * sizeof (png_color));
+ 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];
+ }
+ png_ptr->palette = palette;
+ png_ptr->num_palette = num;
+ png_read_PLTE(png_ptr, info, palette, num);
+}
+
+void
+png_handle_gAMA(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ png_uint_32 igamma;
+ float gamma;
+ png_byte buf[4];
+
+ if (length != 4)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ igamma = png_get_uint_32(buf);
+ /* check for zero gamma */
+ if (!igamma)
+ return;
+
+ gamma = (float)igamma / (float)100000.0;
+ png_read_gAMA(png_ptr, info, gamma);
+ png_ptr->gamma = gamma;
+}
+
+void
+png_handle_sBIT(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ int slen;
+ png_byte buf[4];
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ slen = 3;
+ else
+ slen = png_ptr->channels;
+
+ if (length != (png_uint_32)slen)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, length);
+ 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.alpha = buf[1];
+ }
+ png_read_sBIT(png_ptr, info, &(png_ptr->sig_bit));
+}
+
+void
+png_handle_cHRM(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ png_byte buf[4];
+ png_uint_32 v;
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+
+ if (length != 32)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ white_x = (float)v / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ white_y = (float)v / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ red_x = (float)v / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ red_y = (float)v / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ green_x = (float)v / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ green_y = (float)v / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ blue_x = (float)v / (float)100000.0;
+
+ png_crc_read(png_ptr, buf, 4);
+ v = png_get_uint_32(buf);
+ blue_y = (float)v / (float)100000.0;
+
+ png_read_cHRM(png_ptr, info,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+}
+
+void
+png_handle_tRNS(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (length > png_ptr->num_palette)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_ptr->trans = png_malloc(png_ptr, length);
+ png_crc_read(png_ptr, png_ptr->trans, length);
+ png_ptr->num_trans = (int)length;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_byte buf[6];
+
+ if (length != 6)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, length);
+ png_ptr->num_trans = 3;
+ 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_crc_skip(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_error(png_ptr, "Invalid tRNS chunk");
+
+ png_read_tRNS(png_ptr, info, png_ptr->trans, png_ptr->num_trans,
+ &(png_ptr->trans_values));
+}
+
+void
+png_handle_bKGD(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ int truelen;
+ png_byte buf[6];
+
+ 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 != (png_uint_32)truelen)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, length);
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_ptr->background.index = buf[0];
+ else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
+ 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_read_bKGD(png_ptr, info, &(png_ptr->background));
+}
+
+void
+png_handle_hIST(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ int num, i;
+
+ if (length != 2 * png_ptr->num_palette)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ num = (int)length / 2;
+ png_ptr->hist = png_malloc(png_ptr, num * sizeof (png_uint_16));
+ 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);
+ }
+ png_read_hIST(png_ptr, info, png_ptr->hist);
+}
+
+void
+png_handle_pHYs(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ if (length != 9)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+
+ res_x = png_get_uint_32(buf);
+ res_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_read_pHYs(png_ptr, info, res_x, res_y, unit_type);
+}
+
+void
+png_handle_oFFs(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 offset_x, offset_y;
+ int unit_type;
+
+ if (length != 9)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+
+ offset_x = png_get_uint_32(buf);
+ offset_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_read_oFFs(png_ptr, info, offset_x, offset_y, unit_type);
+}
+
+void
+png_handle_tIME(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ png_byte buf[7];
+ png_time mod_time;
+
+ if (length != 7)
+ {
+ png_crc_skip(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 7);
+
+ 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_read_tIME(png_ptr, info, &mod_time);
+}
+
+/* note: this does not correctly handle chunks that are > 64K */
+void
+png_handle_tEXt(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ char *key, *text;
+
+ text = NULL;
+
+ key = (char *)png_large_malloc(png_ptr, length + 1);
+ png_crc_read(png_ptr, (png_byte *)key, length);
+ key[(png_size_t)length] = '\0';
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ if (text != key + (png_size_t)length)
+ text++;
+
+ png_read_tEXt(png_ptr, info, key, text, length - (text - key));
+}
+
+/* note: this does not correctly handle chunks that are > 64K compressed */
+void
+png_handle_zTXt(png_struct *png_ptr, png_info *info, png_uint_32 length)
+{
+ char *key, *text;
+ int ret;
+ png_uint_32 text_size, key_size;
+
+ text = NULL;
+
+ key = png_large_malloc(png_ptr, length + 1);
+ png_crc_read(png_ptr, (png_byte *)key, length);
+ key[(png_size_t)length] = '\0';
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt can't have zero text */
+ if (text == key + (png_size_t)length)
+ {
+ png_large_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ if (*text) /* check compression byte */
+ {
+ png_large_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ png_ptr->zstream->next_in = (png_byte *)text;
+ png_ptr->zstream->avail_in = (uInt)(length - (text - key));
+ png_ptr->zstream->next_out = png_ptr->zbuf;
+ png_ptr->zstream->avail_out = (png_size_t)png_ptr->zbuf_size;
+
+ key_size = text - key;
+ text_size = 0;
+ text = NULL;
+
+ 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_large_free(png_ptr, key);
+ png_large_free(png_ptr, text);
+ return;
+ }
+ if (!png_ptr->zstream->avail_out || ret == Z_STREAM_END)
+ {
+ if (!text)
+ {
+ text = png_malloc(png_ptr,
+ png_ptr->zbuf_size - png_ptr->zstream->avail_out +
+ key_size + 1);
+ memcpy(text + (png_size_t)key_size, png_ptr->zbuf,
+ (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream->avail_out));
+ memcpy(text, key, (png_size_t)key_size);
+ text_size = key_size + (png_size_t)png_ptr->zbuf_size -
+ png_ptr->zstream->avail_out;
+ *(text + (png_size_t)text_size) = '\0';
+ }
+ else
+ {
+ char *tmp;
+
+ tmp = text;
+ text = png_large_malloc(png_ptr, text_size +
+ png_ptr->zbuf_size - png_ptr->zstream->avail_out + 1);
+ memcpy(text, tmp, (png_size_t)text_size);
+ png_large_free(png_ptr, tmp);
+ memcpy(text + (png_size_t)text_size, png_ptr->zbuf,
+ (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream->avail_out));
+ text_size += png_ptr->zbuf_size - png_ptr->zstream->avail_out;
+ *(text + (png_size_t)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_large_free(png_ptr, key);
+ png_large_free(png_ptr, text);
+ return;
+ }
+
+ png_large_free(png_ptr, key);
+ key = text;
+ text += (png_size_t)key_size;
+ text_size -= key_size;
+
+ png_read_zTXt(png_ptr, info, key, text, text_size, 0);
+}
+
+/* Combines the row recently read in with the previous 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 pixels 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_struct *png_ptr, png_byte *row,
+ int mask)
+{
+ if (mask == 0xff)
+ {
+ 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_byte *sp;
+ png_byte *dp;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ shift = 7;
+ m = 0x80;
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (value << shift);
+ }
+
+ if (shift == 0)
+ {
+ shift = 7;
+ sp++;
+ dp++;
+ }
+ else
+ shift--;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ shift = 6;
+ m = 0x80;
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (value << shift);
+ }
+
+ if (shift == 0)
+ {
+ shift = 6;
+ sp++;
+ dp++;
+ }
+ else
+ shift -= 2;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ shift = 4;
+ m = 0x80;
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (value << shift);
+ }
+
+ if (shift == 0)
+ {
+ shift = 4;
+ sp++;
+ dp++;
+ }
+ else
+ shift -= 4;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ default:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ png_uint_32 i;
+ int pixel_bytes, m;
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ memcpy(dp, sp, pixel_bytes);
+ }
+
+ sp += pixel_bytes;
+ dp += pixel_bytes;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ }
+ }
+}
+
+void
+png_do_read_interlace(png_row_info *row_info, png_byte *row, int pass)
+{
+ if (row && row_info)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_byte *sp, *dp;
+ int sshift, dshift;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dp = row + (png_size_t)((final_width - 1) >> 3);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ for (i = row_info->width; i; i--)
+ {
+ v = (*sp >> sshift) & 0x1;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == 7)
+ {
+ dshift = 0;
+ dp--;
+ }
+ else
+ dshift++;
+ }
+ if (sshift == 7)
+ {
+ sshift = 0;
+ sp--;
+ }
+ else
+ sshift++;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp, *dp;
+ int sshift, dshift;
+ png_byte v;
+ png_uint_32 i, j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+ dp = row + (png_size_t)((final_width - 1) >> 2);
+ dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+ for (i = row_info->width; i; i--)
+ {
+ v = (*sp >> sshift) & 0x3;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (v << dshift);
+ if (dshift == 6)
+ {
+ dshift = 0;
+ dp--;
+ }
+ else
+ dshift += 2;
+ }
+ if (sshift == 6)
+ {
+ sshift = 0;
+ sp--;
+ }
+ else
+ sshift += 2;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp, *dp;
+ int sshift, dshift;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+ dp = row + (png_size_t)((final_width - 1) >> 1);
+ dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+ for (i = row_info->width; i; i--)
+ {
+ v = (*sp >> sshift) & 0xf;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (v << dshift);
+ if (dshift == 4)
+ {
+ dshift = 0;
+ dp--;
+ }
+ else
+ dshift = 4;
+ }
+ if (sshift == 4)
+ {
+ sshift = 0;
+ sp--;
+ }
+ else
+ sshift = 4;
+ }
+ break;
+ }
+ default:
+ {
+ png_byte *sp, *dp;
+ png_byte v[8];
+ png_uint_32 i;
+ int j;
+ int pixel_bytes;
+
+ pixel_bytes = (row_info->pixel_depth >> 3);
+
+ sp = row + (png_size_t)((row_info->width - 1) * pixel_bytes);
+ dp = row + (png_size_t)((final_width - 1) * pixel_bytes);
+ for (i = row_info->width; i; i--)
+ {
+ memcpy(v, sp, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ 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);
+ }
+}
+
+void
+png_read_filter_row(png_row_info *row_info, png_byte *row,
+ png_byte *prev_row, int filter)
+{
+ switch (filter)
+ {
+ case 0:
+ break;
+ case 1:
+ {
+ png_uint_32 i;
+ int bpp;
+ png_byte *rp;
+ png_byte *lp;
+
+ bpp = (row_info->pixel_depth + 7) / 8;
+ for (i = (png_uint_32)bpp, rp = row + bpp, lp = row;
+ i < row_info->rowbytes; i++, rp++, lp++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff);
+ }
+ break;
+ }
+ case 2:
+ {
+ png_uint_32 i;
+ png_byte *rp;
+ png_byte *pp;
+
+ for (i = 0, rp = row, pp = prev_row;
+ i < row_info->rowbytes; i++, rp++, pp++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp)) & 0xff);
+ }
+ break;
+ }
+ case 3:
+ {
+ png_uint_32 i;
+ int bpp;
+ png_byte *rp;
+ png_byte *pp;
+ png_byte *lp;
+
+ bpp = (row_info->pixel_depth + 7) / 8;
+ for (i = 0, rp = row, pp = prev_row;
+ i < (png_uint_32)bpp; i++, rp++, pp++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp) / 2)) & 0xff);
+ }
+ for (lp = row; i < row_info->rowbytes; i++, rp++, lp++, pp++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ (int)(*pp + *lp) / 2) & 0xff);
+ }
+ break;
+ }
+ case 4:
+ {
+ int bpp;
+ png_uint_32 i;
+ png_byte *rp;
+ png_byte *pp;
+ png_byte *lp;
+ png_byte *cp;
+
+ bpp = (row_info->pixel_depth + 7) / 8;
+ for (i = 0, rp = row, pp = prev_row,
+ lp = row - bpp, cp = prev_row - bpp;
+ i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp;
+ if (i >= (png_uint_32)bpp)
+ {
+ c = *cp;
+ a = *lp;
+ }
+ else
+ {
+ a = c = 0;
+ }
+ 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;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void
+png_read_finish_row(png_struct *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;
+ memset(png_ptr->prev_row, 0, (png_size_t)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))
+ {
+ 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;
+ }
+ } while (png_ptr->iwidth == 0);
+
+ if (png_ptr->pass < 7)
+ return;
+ }
+
+ if (!png_ptr->zlib_finished)
+ {
+ char extra;
+ int ret;
+
+ png_ptr->zstream->next_out = (Byte *)&extra;
+ png_ptr->zstream->avail_out = (uInt)1;
+ do
+ {
+ if (!(png_ptr->zstream->avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte buf[4];
+ png_uint_32 crc;
+
+ png_read_data(png_ptr, buf, 4);
+ crc = png_get_uint_32(buf);
+ if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
+ (png_ptr->crc & 0xffffffffL))
+ png_error(png_ptr, "Bad CRC value");
+
+ png_read_data(png_ptr, buf, 4);
+ png_ptr->idat_size = png_get_uint_32(buf);
+ png_reset_crc(png_ptr);
+
+ png_crc_read(png_ptr, buf, 4);
+ if (memcmp(buf, 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_AT_LAST_IDAT;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, "Compression Error");
+
+ if (!(png_ptr->zstream->avail_out))
+ png_error(png_ptr, "Extra compressed data");
+
+ } while (1);
+ 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_AT_LAST_IDAT;
+}
+
+void
+png_read_start_row(png_struct *png_ptr)
+{
+ int max_pixel_depth;
+ png_uint_32 rowbytes;
+
+ 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];
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ png_ptr->pixel_depth + 7) >> 3) + 1;
+ }
+ 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 ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
+ {
+ max_pixel_depth = 8;
+ }
+
+ if (png_ptr->transformations & (PNG_EXPAND | PNG_PACK))
+ {
+ 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;
+ }
+ }
+ }
+
+ if (png_ptr->transformations & PNG_RGBA)
+ {
+ if (max_pixel_depth < 32)
+ max_pixel_depth = 32;
+ }
+
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ {
+ if ((png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
+ png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (max_pixel_depth <= 16)
+ max_pixel_depth = 32;
+ else if (max_pixel_depth <= 32)
+ max_pixel_depth = 64;
+ }
+ else
+ {
+ if (max_pixel_depth <= 8)
+ max_pixel_depth = 24;
+ else if (max_pixel_depth <= 16)
+ max_pixel_depth = 48;
+ }
+ }
+
+ /* align the width on the next larger 8 pixels. Mainly used
+ for interlacing */
+ rowbytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
+ /* calculate the maximum bytes needed, adding a byte and a pixel
+ for safety sake */
+ rowbytes = ((rowbytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
+ 1 + ((max_pixel_depth + 7) >> 3);
+#ifdef PNG_MAX_MALLOC_64K
+ if (rowbytes > 65536L)
+ png_error(png_ptr, "This image requires a row greater then 64KB");
+#endif
+ png_ptr->row_buf = (png_byte *)png_large_malloc(png_ptr, rowbytes);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (png_ptr->rowbytes + 1 > 65536L)
+ png_error(png_ptr, "This image requires a row greater then 64KB");
+#endif
+ png_ptr->prev_row = png_large_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+
+ memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
+
+ png_ptr->row_init = 1;
+
+ /* if we have to do any modifications of values for the transformations,
+ do them here */
+}
+
diff --git a/pngstub.c b/pngstub.c
new file mode 100644
index 000000000..6ae1469eb
--- /dev/null
+++ b/pngstub.c
@@ -0,0 +1,387 @@
+
+/* pngstub.c - stub functions for i/o and memory allocation
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+
+ This file provides a location for all input/output, memory location,
+ and error handling. Users which need special handling in these areas
+ are expected to modify the code in this file to meet their needs. See
+ the instructions at each function. */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Write the data to whatever output you are using. The default
+ routine writes to a file pointer. If you need to write to something
+ else, this is the place to do it. We suggest saving the old code
+ for future use, possibly in a #define. 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 then 64K on a 16 bit machine. The cast
+ to png_size_t is there for insurance, but if you are having problems
+ with it, you can take it out. Just be sure to cast length to whatever
+ fwrite needs in that spot if you don't have a function prototype for
+ it. */
+void
+png_write_data(png_struct *png_ptr, png_byte *data, png_uint_32 length)
+{
+ png_uint_32 check;
+
+ check = fwrite(data, 1, (png_size_t)length, png_ptr->fp);
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+
+/* Read the data from whatever input you are using. The default
+ routine reads from a file pointer. If you need to read from something
+ else, this is the place to do it. We suggest saving the old code
+ for future use. 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. The cast
+ to png_size_t is there for insurance, but if you are having problems
+ with it, you can take it out. Just be sure to cast length to whatever
+ fread needs in that spot if you don't have a function prototype for
+ it. */
+void
+png_read_data(png_struct *png_ptr, png_byte *data, png_uint_32 length)
+{
+ png_uint_32 check;
+
+ check = fread(data, 1, (size_t)length, png_ptr->fp);
+ if (check != length)
+ {
+ png_error(png_ptr, "Read Error");
+ }
+}
+
+/* Initialize the input/output for the png file. If you change
+ the read and write routines, you will probably need to change
+ this routine (or write your own). If you change the parameters
+ of this routine, remember to change png.h also. */
+void
+png_init_io(png_struct *png_ptr, FILE *fp)
+{
+ png_ptr->fp = fp;
+}
+
+/* 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 compilers have this habit of not giving you 64K chunks
+ that start on the segment in DOS mode. This has not been observed
+ in Windows, and of course it doesn't matter in 32 bit mode, as there
+ are no segments. Now libpng doesn't need that much memory normally,
+ but zlib does, so we have to normalize it, if necessary. It would be
+ better if zlib worked in less then 64K, but it doesn't, so we
+ have to deal with it. Truely, we are misusing farmalloc here,
+ as it is designed for use with huge pointers, which don't care
+ about segments. So we allocate a large amount of memory, and
+ divvy off segments when needed.
+ */
+#ifdef __TURBOC__
+#ifndef __WIN32__
+
+/* NUM_SEG is the number of segments allocated at once */
+#define NUM_SEG 4
+typedef struct borland_seg_struct
+{
+ void *mem_ptr;
+ void *seg_ptr[NUM_SEG];
+ int seg_used[NUM_SEG];
+ int num_used;
+} borland_seg;
+
+borland_seg *save_array;
+int num_save_array;
+int max_save_array;
+
+#endif
+#endif
+
+void *
+png_large_malloc(png_struct *png_ptr, png_uint_32 size)
+{
+ void *ret;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+#ifdef __TURBOC__
+# ifdef __WIN32__
+ ret = farmalloc(size);
+# else
+
+ if (size == 65536L)
+ {
+ unsigned long offset;
+ if (!save_array)
+ {
+ ret = farmalloc(size);
+ offset = (unsigned long)(ret);
+ offset &= 0xffffL;
+ }
+ else
+ {
+ ret = (void *)0;
+ }
+ if (save_array || offset)
+ {
+ int i, j;
+
+ if (ret)
+ farfree(ret);
+ ret = (void *)0;
+
+ if (!save_array)
+ {
+ unsigned long offset;
+ png_byte huge *ptr;
+ int i;
+
+ num_save_array = 1;
+ save_array = malloc(num_save_array * sizeof (borland_seg));
+ if (!save_array)
+ png_error(png_ptr, "Out of Memory");
+ save_array->mem_ptr = farmalloc(
+ (unsigned long)(NUM_SEG) * 65536L + 65528L);
+ if (!save_array->mem_ptr)
+ png_error(png_ptr, "Out of Memory");
+ offset = (unsigned long)(ret);
+ offset &= 0xffffL;
+ ptr = save_array->mem_ptr;
+ if (offset)
+ ptr += 65536L - offset;
+ for (i = 0; i < NUM_SEG; i++, ptr += 65536L)
+ {
+ save_array->seg_ptr[i] = ptr;
+ save_array->seg_used[i] = 0;
+ }
+ save_array->num_used = 0;
+ }
+
+ for (i = 0; i < num_save_array; i++)
+ {
+ for (j = 0; j < NUM_SEG; j++)
+ {
+ if (!save_array[i].seg_used[j])
+ {
+ ret = save_array[i].seg_ptr[j];
+ save_array[i].seg_used[j] = 1;
+ save_array[i].num_used++;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+
+ if (!ret)
+ {
+ unsigned long offset;
+ png_byte huge *ptr;
+
+ save_array = realloc(save_array,
+ (num_save_array + 1) * sizeof (borland_seg));
+ if (!save_array)
+ png_error(png_ptr, "Out of Memory");
+ save_array[num_save_array].mem_ptr = farmalloc(
+ (unsigned long)(NUM_SEG) * 65536L + 65528L);
+ if (!save_array[num_save_array].mem_ptr)
+ png_error(png_ptr, "Out of Memory");
+ offset = (unsigned long)(ret);
+ offset &= 0xffffL;
+ ptr = save_array[num_save_array].mem_ptr;
+ if (offset)
+ ptr += 65536L - offset;
+ for (i = 0; i < NUM_SEG; i++, ptr += 65536L)
+ {
+ save_array[num_save_array].seg_ptr[i] = ptr;
+ save_array[num_save_array].seg_used[i] = 0;
+ }
+ ret = save_array[num_save_array].seg_ptr[0];
+ save_array[num_save_array].seg_used[0] = 1;
+ save_array[num_save_array].num_used = 1;
+ num_save_array++;
+ }
+ }
+ }
+ else
+ {
+ ret = farmalloc(size);
+ }
+
+# endif /* __WIN32__ */
+#else /* __TURBOC__ */
+# ifdef _MSC_VER
+ ret = halloc(size, 1);
+# else
+ /* everybody else, so normal malloc should do it. */
+ ret = malloc(size);
+# endif
+#endif
+
+ if (!ret)
+ {
+ png_error(png_ptr, "Out of Memory");
+ }
+
+ return ret;
+}
+
+/* free a pointer allocated by png_large_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_large_free(png_struct *png_ptr, void *ptr)
+{
+ if (!png_ptr)
+ return;
+
+ if (ptr != (void *)0)
+ {
+#ifdef __TURBOC__
+# ifndef __WIN32__
+ int i, j;
+
+ for (i = 0; i < num_save_array; i++)
+ {
+ for (j = 0; j < NUM_SEG; j++)
+ {
+ if (ptr == save_array[i].seg_ptr[j])
+ {
+printf("freeing pointer: i, j: %d, %d\n", i, j);
+ save_array[i].seg_used[j] = 0;
+ ptr = 0;
+ save_array[i].num_used--;
+ if (!save_array[i].num_used)
+ {
+ int k;
+printf("freeing array: %d\n", i);
+ num_save_array--;
+ farfree(save_array[i].mem_ptr);
+ for (k = i; k < num_save_array; k++)
+ save_array[k] = save_array[k + 1];
+ if (!num_save_array)
+ {
+ free(save_array);
+ save_array = 0;
+ }
+ }
+ break;
+ }
+ }
+ if (!ptr)
+ break;
+ }
+
+# endif
+ if (ptr)
+ farfree(ptr);
+#else
+# ifdef _MSC_VER
+ hfree(ptr);
+# else
+ free(ptr);
+# endif
+#endif
+ }
+}
+
+/* Allocate memory. This is called for smallish blocks only It
+ should not get anywhere near 64K. */
+void *
+png_malloc(png_struct *png_ptr, png_uint_32 size)
+{
+ void *ret;
+
+ if (!png_ptr)
+ return ((void *)0);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+ ret = malloc((png_size_t)size);
+
+ if (!ret)
+ {
+ png_error(png_ptr, "Out of Memory");
+ }
+
+ return ret;
+}
+
+/* Reallocate memory. This will not get near 64K on a
+ even marginally reasonable file. */
+void *
+png_realloc(png_struct *png_ptr, void *ptr, png_uint_32 size)
+{
+ void *ret;
+
+ if (!png_ptr)
+ return ((void *)0);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+ ret = realloc(ptr, (png_size_t)size);
+
+ if (!ret)
+ {
+ png_error(png_ptr, "Out of Memory");
+ }
+
+ return ret;
+}
+
+/* free a pointer allocated by png_malloc(). In the default
+ configuration, png_ptr is not used, but is passed incase it
+ is needed. If ptr is NULL, return without taking any action. */
+void
+png_free(png_struct *png_ptr, void *ptr)
+{
+ if (!png_ptr)
+ return;
+
+ if (ptr != (void *)0)
+ free(ptr);
+}
+
+/* This function is called whenever there is an error. Replace with
+ however you wish to handle the error. Note that this function
+ MUST NOT return, or the program will crash */
+void
+png_error(png_struct *png_ptr, char *message)
+{
+ fprintf(stderr, "libpng error: %s\n", message);
+
+ longjmp(png_ptr->jmpbuf, 1);
+}
+
+/* This function is called when there is a warning, but the library
+ thinks it can continue anyway. You 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. */
+void
+png_warning(png_struct *png_ptr, char *message)
+{
+ if (!png_ptr)
+ return;
+
+ fprintf(stderr, "libpng warning: %s\n", message);
+}
+
diff --git a/pngtest.c b/pngtest.c
new file mode 100644
index 000000000..ba60b134d
--- /dev/null
+++ b/pngtest.c
@@ -0,0 +1,180 @@
+/* pngtest.c - a simple test program to test libpng
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "png.h"
+
+#ifdef __TURBOC__
+#include <mem.h>
+#endif
+
+/* defined so I can write to a file on gui/windowing platforms */
+#define STDERR stderr
+
+/* input and output filenames */
+char inname[] = "pngtest.png";
+char outname[] = "pngout.png";
+
+png_struct read_ptr;
+png_struct write_ptr;
+png_info info_ptr;
+png_info end_info;
+
+char inbuf[256], outbuf[256];
+
+int main()
+{
+ FILE *fpin, *fpout;
+ png_byte *row_buf;
+ png_uint_32 rowbytes;
+ png_uint_32 y;
+ int channels, num_pass, pass;
+
+ row_buf = (png_byte *)0;
+
+ fpin = fopen(inname, "rb");
+ if (!fpin)
+ {
+ fprintf(STDERR, "Could not find input file %s\n", inname);
+ return -1;
+ }
+
+ fpout = fopen(outname, "wb");
+ if (!fpin)
+ {
+ fprintf(STDERR, "could not open output file %s\n", outname);
+ fclose(fpin);
+ return -1;
+ }
+
+ if (setjmp(read_ptr.jmpbuf))
+ {
+ fprintf(STDERR, "libpng read error\n");
+ fclose(fpin);
+ fclose(fpout);
+ return -1;
+ }
+
+ if (setjmp(write_ptr.jmpbuf))
+ {
+ fprintf(STDERR, "libpng write error\n");
+ fclose(fpin);
+ fclose(fpout);
+ return -1;
+ }
+
+ png_read_init(&read_ptr);
+ png_write_init(&write_ptr);
+ png_info_init(&info_ptr);
+ png_info_init(&end_info);
+
+ png_init_io(&read_ptr, fpin);
+ png_init_io(&write_ptr, fpout);
+
+ png_read_info(&read_ptr, &info_ptr);
+ png_write_info(&write_ptr, &info_ptr);
+
+ if ((info_ptr.color_type & 3) == 2)
+ channels = 3;
+ else
+ channels = 1;
+ if (info_ptr.color_type & 4)
+ channels++;
+
+ rowbytes = ((info_ptr.width * info_ptr.bit_depth * channels + 7) >> 3);
+ row_buf = (png_byte *)malloc((size_t)rowbytes);
+ if (!row_buf)
+ {
+ fprintf(STDERR, "no memory to allocate row buffer\n");
+ png_read_destroy(&read_ptr, &info_ptr, (png_info *)0);
+ png_write_destroy(&write_ptr);
+ fclose(fpin);
+ fclose(fpout);
+ return -1;
+ }
+
+ if (info_ptr.interlace_type)
+ {
+ num_pass = png_set_interlace_handling(&read_ptr);
+ num_pass = png_set_interlace_handling(&write_ptr);
+ }
+ else
+ {
+ num_pass = 1;
+ }
+
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ for (y = 0; y < info_ptr.height; y++)
+ {
+ png_read_rows(&read_ptr, &row_buf, (png_byte **)0, 1);
+ png_write_rows(&write_ptr, &row_buf, 1);
+ }
+ }
+
+ png_read_end(&read_ptr, &end_info);
+ png_write_end(&write_ptr, &end_info);
+
+ png_read_destroy(&read_ptr, &info_ptr, &end_info);
+ png_write_destroy(&write_ptr);
+
+ fclose(fpin);
+ fclose(fpout);
+
+ free(row_buf);
+
+ fpin = fopen(inname, "rb");
+
+ if (!fpin)
+ {
+ fprintf(STDERR, "could not find file %s\n", inname);
+ return -1;
+ }
+
+ fpout = fopen(outname, "rb");
+ if (!fpout)
+ {
+ fprintf(STDERR, "could not find file %s\n", outname);
+ fclose(fpin);
+ return -1;
+ }
+
+ while (1)
+ {
+ int num_in, num_out;
+
+ num_in = fread(inbuf, 1, 256, fpin);
+ num_out = fread(outbuf, 1, 256, fpout);
+
+ if (num_in != num_out)
+ {
+ fprintf(STDERR, "files are of a different size\n");
+ fclose(fpin);
+ fclose(fpout);
+ return -1;
+ }
+
+ if (!num_in)
+ break;
+
+ if (memcmp(inbuf, outbuf, num_in))
+ {
+ fprintf(STDERR, "files are different\n");
+ fclose(fpin);
+ fclose(fpout);
+ return -1;
+ }
+ }
+
+ fclose(fpin);
+ fclose(fpout);
+ fprintf(STDERR, "libpng passes test\n");
+
+ return 0;
+}
diff --git a/pngtest.png b/pngtest.png
new file mode 100644
index 000000000..67506634c
--- /dev/null
+++ b/pngtest.png
Binary files differ
diff --git a/pngtodo.txt b/pngtodo.txt
new file mode 100644
index 000000000..b52a3aaa7
--- /dev/null
+++ b/pngtodo.txt
@@ -0,0 +1,22 @@
+pngtodo.txt - list of things to do for libpng
+
+ allow user to #define out unused transformations
+ medium memory model support
+ overlaying one image on top of another
+ optional palette creation
+ histogram creation
+ text conversion between different code types
+ cHRM transformation
+ support for other chunks being defined (sCAl, the gIF series,
+ and others that people come up with).
+ push reader
+ pull writer
+ better dithering
+ keep up with public chunks
+ other compression libraries
+ more exotic interlace handling
+ better filtering
+ C++ wrapper
+ other languages
+ comments of > 64K
+
diff --git a/pngtrans.c b/pngtrans.c
new file mode 100644
index 000000000..02b00bcbc
--- /dev/null
+++ b/pngtrans.c
@@ -0,0 +1,192 @@
+
+/* pngtrans.c - transforms the data in a row
+ routines used by both readers and writers
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* turn on bgr to rgb mapping */
+void
+png_set_bgr(png_struct *png_ptr)
+{
+ png_ptr->transformations |= PNG_BGR;
+}
+
+/* turn on 16 bit byte swapping */
+void
+png_set_swap(png_struct *png_ptr)
+{
+ if (png_ptr->bit_depth == 16)
+ png_ptr->transformations |= PNG_SWAP_BYTES;
+}
+
+/* turn on pixel packing */
+void
+png_set_packing(png_struct *png_ptr)
+{
+ if (png_ptr->bit_depth < 8)
+ {
+ png_ptr->transformations |= PNG_PACK;
+ png_ptr->usr_bit_depth = 8;
+ }
+}
+
+void
+png_set_shift(png_struct *png_ptr, png_color_8 *true_bits)
+{
+ png_ptr->transformations |= PNG_SHIFT;
+ png_ptr->shift = *true_bits;
+}
+
+int
+png_set_interlace_handling(png_struct *png_ptr)
+{
+ if (png_ptr->interlaced)
+ {
+ png_ptr->transformations |= PNG_INTERLACE;
+ return 7;
+ }
+
+ return 1;
+}
+
+void
+png_set_rgbx(png_struct *png_ptr)
+{
+ png_ptr->transformations |= PNG_RGBA;
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB &&
+ png_ptr->bit_depth == 8)
+ png_ptr->usr_channels = 4;
+}
+
+void
+png_set_xrgb(png_struct *png_ptr)
+{
+ png_ptr->transformations |= PNG_XRGB;
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB &&
+ png_ptr->bit_depth == 8)
+ png_ptr->usr_channels = 4;
+}
+
+void
+png_set_invert_mono(png_struct *png_ptr)
+{
+ png_ptr->transformations |= PNG_INVERT_MONO;
+}
+
+/* invert monocrome grayscale data */
+void
+png_do_invert(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->bit_depth == 1 &&
+ row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_byte *rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row;
+ i < row_info->rowbytes;
+ i++, rp++)
+ {
+ *rp = ~(*rp);
+ }
+ }
+}
+
+/* swaps byte order on 16 bit depth images */
+void
+png_do_swap(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->bit_depth == 16)
+ {
+ png_byte *rp, t;
+ png_uint_32 i;
+
+ for (i = 0, rp = row;
+ i < row_info->width * row_info->channels;
+ i++, rp += 2)
+ {
+ t = *rp;
+ *rp = *(rp + 1);
+ *(rp + 1) = t;
+ }
+ }
+}
+
+/* swaps red and blue */
+void
+png_do_bgr(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && (row_info->color_type & 2))
+ {
+ if (row_info->color_type == 2 && row_info->bit_depth == 8)
+ {
+ png_byte *rp, t;
+ png_uint_32 i;
+
+ for (i = 0, rp = row;
+ i < row_info->width;
+ i++, rp += 3)
+ {
+ t = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = t;
+ }
+ }
+ else if (row_info->color_type == 6 && row_info->bit_depth == 8)
+ {
+ png_byte *rp, t;
+ png_uint_32 i;
+
+ for (i = 0, rp = row;
+ i < row_info->width;
+ i++, rp += 4)
+ {
+ t = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = t;
+ }
+ }
+ else if (row_info->color_type == 2 && row_info->bit_depth == 16)
+ {
+ png_byte *rp, t[2];
+ png_uint_32 i;
+
+ for (i = 0, rp = row;
+ i < row_info->width;
+ i++, rp += 6)
+ {
+ t[0] = *rp;
+ t[1] = *(rp + 1);
+ *rp = *(rp + 4);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 4) = t[0];
+ *(rp + 5) = t[1];
+ }
+ }
+ else if (row_info->color_type == 6 && row_info->bit_depth == 16)
+ {
+ png_byte *rp, t[2];
+ png_uint_32 i;
+
+ for (i = 0, rp = row;
+ i < row_info->width;
+ i++, rp += 8)
+ {
+ t[0] = *rp;
+ t[1] = *(rp + 1);
+ *rp = *(rp + 4);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 4) = t[0];
+ *(rp + 5) = t[1];
+ }
+ }
+ }
+}
+
diff --git a/pngwrite.c b/pngwrite.c
new file mode 100644
index 000000000..ac7e22f69
--- /dev/null
+++ b/pngwrite.c
@@ -0,0 +1,408 @@
+
+/* pngwrite.c - general routines to write a png file
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+/* 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 encurage you to supply a PNG_INFO_ flag, and check
+ info->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_struct *png_ptr, png_info *info)
+{
+ png_write_sig(png_ptr); /* write PNG signature */
+ /* write IHDR information. */
+ png_write_IHDR(png_ptr, info->width, info->height, info->bit_depth,
+ info->color_type, info->compression_type, info->filter_type,
+ info->interlace_type);
+ /* the rest of these check to see if the valid field has the appropriate
+ flag set, and if it does, writes the chunk. */
+ if (info->valid & PNG_INFO_gAMA)
+ png_write_gAMA(png_ptr, info->gamma);
+ if (info->valid & PNG_INFO_sBIT)
+ png_write_sBIT(png_ptr, &(info->sig_bit), info->color_type);
+ if (info->valid & PNG_INFO_cHRM)
+ png_write_cHRM(png_ptr,
+ info->x_white, info->y_white,
+ info->x_red, info->y_red,
+ info->x_green, info->y_green,
+ info->x_blue, info->y_blue);
+ if (info->valid & PNG_INFO_PLTE)
+ png_write_PLTE(png_ptr, info->palette, info->num_palette);
+ if (info->valid & PNG_INFO_tRNS)
+ png_write_tRNS(png_ptr, info->trans, &(info->trans_values),
+ info->num_trans, info->color_type);
+ if (info->valid & PNG_INFO_bKGD)
+ png_write_bKGD(png_ptr, &(info->background), info->color_type);
+ if (info->valid & PNG_INFO_hIST)
+ png_write_hIST(png_ptr, info->hist, info->num_palette);
+ if (info->valid & PNG_INFO_pHYs)
+ png_write_pHYs(png_ptr, info->x_pixels_per_unit,
+ info->y_pixels_per_unit, info->phys_unit_type);
+ if (info->valid & PNG_INFO_oFFs)
+ png_write_oFFs(png_ptr, info->x_offset, info->y_offset,
+ info->offset_unit_type);
+ if (info->valid & PNG_INFO_tIME)
+ png_write_tIME(png_ptr, &(info->mod_time));
+ /* Check to see if we need to write text chunks */
+ if (info->num_text)
+ {
+ int i; /* local counter */
+
+ /* loop through the text chunks */
+ for (i = 0; i < info->num_text; i++)
+ {
+ /* if chunk is compressed */
+ if (info->text[i].compression >= 0)
+ {
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info->text[i].key,
+ info->text[i].text, info->text[i].text_length,
+ info->text[i].compression);
+ }
+ else
+ {
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info->text[i].key,
+ info->text[i].text, info->text[i].text_length);
+ }
+ }
+ }
+}
+
+/* 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_struct *png_ptr, png_info *info)
+{
+ /* see if user wants us to write information chunks */
+ if (info)
+ {
+ /* check to see if user has supplied a time chunk */
+ if (info->valid & PNG_INFO_tIME)
+ png_write_tIME(png_ptr, &(info->mod_time));
+ /* check to see if we need to write comment chunks */
+ if (info->num_text)
+ {
+ int i; /* local index variable */
+
+ /* loop through comment chunks */
+ for (i = 0; i < info->num_text; i++)
+ {
+ /* check to see if comment is to be compressed */
+ if (info->text[i].compression >= 0)
+ {
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info->text[i].key,
+ info->text[i].text, info->text[i].text_length,
+ info->text[i].compression);
+ }
+ else
+ {
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info->text[i].key,
+ info->text[i].text, info->text[i].text_length);
+ }
+ }
+ }
+ }
+ /* write end of png file */
+ png_write_IEND(png_ptr);
+}
+
+/* initialize the info structure */
+void
+png_info_init(png_info *info)
+{
+ /* set everything to 0 */
+ memset(info, 0, sizeof (png_info));
+}
+
+void
+png_convert_from_struct_tm(png_time *ptime, struct tm *ttime)
+{
+ ptime->year = 1900 + ttime->tm_year;
+ ptime->month = ttime->tm_mon + 1;
+ ptime->day = ttime->tm_mday;
+ ptime->hour = ttime->tm_hour;
+ ptime->minute = ttime->tm_min;
+ ptime->second = ttime->tm_sec;
+}
+
+void
+png_convert_from_time_t(png_time *ptime, time_t ttime)
+{
+ struct tm *tbuf;
+
+ tbuf = gmtime(&ttime);
+ png_convert_from_struct_tm(ptime, tbuf);
+}
+
+/* initialize png structure, and allocate any memory needed */
+void
+png_write_init(png_struct *png_ptr)
+{
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+
+ /* save jump buffer */
+ memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+ /* reset all variables to 0 */
+ memset(png_ptr, 0, sizeof (png_struct));
+ /* restore jump buffer */
+ memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
+ /* initialize zlib */
+ png_ptr->zstream = &(png_ptr->zstream_struct);
+ png_ptr->zstream->zalloc = png_zalloc;
+ png_ptr->zstream->zfree = png_zfree;
+ png_ptr->zstream->opaque = (voidp)png_ptr;
+ deflateInit(png_ptr->zstream, Z_BEST_COMPRESSION);
+ png_ptr->zstream->next_out = png_ptr->zbuf;
+ png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
+}
+
+/* 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_struct *png_ptr, png_byte **row,
+ png_uint_32 num_rows)
+{
+ png_uint_32 i; /* row counter */
+ png_byte **rp; /* row pointer */
+
+ /* 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_struct *png_ptr, png_byte **image)
+{
+ png_uint_32 i; /* row index */
+ int pass, num_pass; /* pass variables */
+ png_byte **rp; /* points to current row */
+
+ /* intialize interlace handling. If image is not interlaced,
+ this will set pass to 1 */
+ num_pass = png_set_interlace_handling(png_ptr);
+ /* 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);
+ }
+ }
+}
+
+/* write a row of image data */
+void
+png_write_row(png_struct *png_ptr, png_byte *row)
+{
+ /* initialize transformations and other stuff if first time */
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ png_write_start_row(png_ptr);
+ }
+
+ /* 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;
+ }
+ }
+
+ /* 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_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);
+
+ /* copy users row into buffer, leaving room for filter byte */
+ memcpy(png_ptr->row_buf + 1, row, (png_size_t)png_ptr->row_info.rowbytes);
+
+ /* 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;
+ }
+ }
+
+ /* handle other transformations */
+ if (png_ptr->transformations)
+ png_do_write_transformations(png_ptr);
+
+ /* filter rows that have been proved to help */
+ if (png_ptr->bit_depth >= 8 && png_ptr->color_type != 3)
+ {
+ /* save row to previous row */
+ memcpy(png_ptr->save_row, png_ptr->row_buf,
+ (png_size_t)png_ptr->row_info.rowbytes + 1);
+
+ /* filter row */
+ png_write_filter_row(&(png_ptr->row_info), png_ptr->row_buf,
+ png_ptr->prev_row);
+
+ /* trade saved pointer and prev pointer so next row references are correctly */
+ { /* scope limiter */
+ png_byte *tptr;
+
+ tptr = png_ptr->prev_row;
+ png_ptr->prev_row = png_ptr->save_row;
+ png_ptr->save_row = tptr;
+ }
+ }
+ else
+ /* set filter row to "none" */
+ png_ptr->row_buf[0] = 0;
+
+ /* set up the zlib input buffer */
+ png_ptr->zstream->next_in = png_ptr->row_buf;
+ png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
+
+#ifdef zlibinout
+/* temp zlib problem */
+{
+ extern FILE *fpzlibin;
+
+ fwrite(png_ptr->row_buf, 1, png_ptr->zstream->avail_in, fpzlibin);
+}
+/* end temp zlib problem */
+#endif
+
+ /* 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)
+ 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);
+
+ /* finish row - updates counters and flushes zlib if last row */
+ png_write_finish_row(png_ptr);
+}
+
+/* free any memory used in png struct */
+void
+png_write_destroy(png_struct *png_ptr)
+{
+ jmp_buf tmp_jmp; /* save jump buffer */
+
+ /* free any memory zlib uses */
+ deflateEnd(png_ptr->zstream);
+ /* free our memory. png_free checks NULL for us. */
+ png_large_free(png_ptr, png_ptr->zbuf);
+ png_large_free(png_ptr, png_ptr->row_buf);
+ png_large_free(png_ptr, png_ptr->prev_row);
+ png_large_free(png_ptr, png_ptr->save_row);
+ /* reset structure */
+ memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+ memset(png_ptr, 0, sizeof (png_struct));
+ memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+}
+
diff --git a/pngwtran.c b/pngwtran.c
new file mode 100644
index 000000000..7423ade34
--- /dev/null
+++ b/pngwtran.c
@@ -0,0 +1,331 @@
+
+/* pngwtran.c - transforms the data in a row for png writers
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* transform the data according to the users wishes. The order of
+ transformations is significant. */
+void
+png_do_write_transformations(png_struct *png_ptr)
+{
+ if (png_ptr->transformations & PNG_RGBA)
+ png_do_write_rgbx(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_XRGB)
+ png_do_write_xrgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->bit_depth);
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+}
+
+/* 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_info *row_info, png_byte *row, png_byte bit_depth)
+{
+ if (row_info && row && row_info->bit_depth == 8 &&
+ row_info->channels == 1)
+ {
+ switch (bit_depth)
+ {
+ case 1:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int mask;
+ png_int_32 i;
+ int v;
+
+ sp = row;
+ dp = row;
+ mask = 0x80;
+ v = 0;
+ for (i = 0; i < row_info->width; i++)
+ {
+ if (*sp)
+ v |= mask;
+ sp++;
+ if (mask > 1)
+ mask >>= 1;
+ else
+ {
+ mask = 0x80;
+ *dp = v;
+ dp++;
+ v = 0;
+ }
+ }
+ if (mask != 0x80)
+ *dp = v;
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ png_int_32 i;
+ int v;
+ png_byte value;
+
+ sp = row;
+ dp = row;
+ shift = 6;
+ v = 0;
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = *sp & 0x3;
+ v |= (value << shift);
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp = v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 2;
+ sp++;
+ }
+ if (shift != 6)
+ *dp = v;
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ png_int_32 i;
+ int v;
+ png_byte value;
+
+ sp = row;
+ dp = row;
+ shift = 4;
+ v = 0;
+ for (i = 0; i < row_info->width; i++)
+ {
+ value = *sp & 0xf;
+ v |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp = v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 4;
+
+ sp++;
+ }
+ if (shift != 4)
+ *dp = v;
+ break;
+ }
+ }
+ row_info->bit_depth = bit_depth;
+ row_info->pixel_depth = bit_depth * row_info->channels;
+ row_info->rowbytes =
+ ((row_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+}
+
+/* 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_info *row_info, png_byte *row, png_color_8 *bit_depth)
+{
+ if (row && row_info &&
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift_start[4], shift_dec[4];
+ int channels;
+
+ 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 dephts, could only be grayscale, so one channel */
+ if (row_info->bit_depth < 8)
+ {
+ png_byte *bp;
+ png_uint_32 i;
+ int j;
+ png_byte mask;
+
+ 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 (bp = row, i = 0; i < row_info->rowbytes; i++, bp++)
+ {
+ int v;
+
+ 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_byte *bp;
+ png_uint_32 i;
+ int j;
+
+ for (bp = row, i = 0; i < row_info->width; i++)
+ {
+ int c;
+
+ for (c = 0; c < channels; c++, bp++)
+ {
+ int v;
+
+ 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_byte *bp;
+ png_uint_32 i;
+ int j;
+
+ for (bp = row, i = 0;
+ i < row_info->width * row_info->channels;
+ i++)
+ {
+ int c;
+
+ for (c = 0; c < channels; c++, bp += 2)
+ {
+ png_uint_16 value, v;
+
+ v = ((png_uint_16)(*bp) << 8) + (png_uint_16)(*(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 = value >> 8;
+ *(bp + 1) = value & 0xff;
+ }
+ }
+ }
+ }
+}
+
+/* remove filler byte after rgb */
+void
+png_do_write_rgbx(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ row_info->bit_depth == 8)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 1, sp = row + 4, dp = row + 3;
+ i < row_info->width;
+ i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp++;
+ }
+ row_info->channels = 3;
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_info->width * 3;
+ }
+}
+
+/* remove filler byte before rgb */
+void
+png_do_write_xrgb(png_row_info *row_info, png_byte *row)
+{
+ if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ row_info->bit_depth == 8)
+ {
+ png_byte *sp, *dp;
+ png_uint_32 i;
+
+ for (i = 0, sp = row, dp = row;
+ i < row_info->width;
+ i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ row_info->channels = 3;
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_info->width * 3;
+ }
+}
+
diff --git a/pngwutil.c b/pngwutil.c
new file mode 100644
index 000000000..89743d750
--- /dev/null
+++ b/pngwutil.c
@@ -0,0 +1,1080 @@
+
+/* pngwutil.c - utilities to write a png file
+
+ libpng 1.0 beta 1 - version 0.71
+ For conditions of distribution and use, see copyright notice in png.h
+ Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
+ June 26, 1995
+ */
+#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, you may have to cast
+ signed numbers (if you use any, most png data is unsigned). */
+void
+png_save_uint_32(png_byte *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);
+}
+
+/* place a 16 bit number into a buffer in png byte order */
+void
+png_save_uint_16(png_byte *buf, png_uint_16 i)
+{
+ buf[0] = (png_byte)((i >> 8) & 0xff);
+ buf[1] = (png_byte)(i & 0xff);
+}
+
+/* write a 32 bit number */
+void
+png_write_uint_32(png_struct *png_ptr, png_uint_32 i)
+{
+ png_byte buf[4];
+
+ 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);
+ png_write_data(png_ptr, buf, 4);
+}
+
+/* write a 16 bit number */
+void
+png_write_uint_16(png_struct *png_ptr, png_uint_16 i)
+{
+ png_byte buf[2];
+
+ buf[0] = (png_byte)((i >> 8) & 0xff);
+ buf[1] = (png_byte)(i & 0xff);
+ png_write_data(png_ptr, buf, 2);
+}
+
+/* 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_struct *png_ptr, png_byte *type,
+ png_byte *data, png_uint_32 length)
+{
+ /* write length */
+ png_write_uint_32(png_ptr, length);
+ /* write chunk name */
+ png_write_data(png_ptr, type, (png_uint_32)4);
+ /* reset the crc and run the chunk name over it */
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, type, (png_uint_32)4);
+ /* write the data and update the crc */
+ if (length)
+ {
+ png_calculate_crc(png_ptr, data, length);
+ png_write_data(png_ptr, data, length);
+ }
+ /* write the crc */
+ png_write_uint_32(png_ptr, ~png_ptr->crc);
+}
+
+/* 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_struct *png_ptr, png_byte *type,
+ png_uint_32 total_length)
+{
+ /* write the length */
+ png_write_uint_32(png_ptr, total_length);
+ /* write the chunk name */
+ png_write_data(png_ptr, type, (png_uint_32)4);
+ /* reset the crc and run it over the chunk name */
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, type, (png_uint_32)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_struct *png_ptr, png_byte *data, png_uint_32 length)
+{
+ /* write the data, and run the crc over it */
+ if (length)
+ {
+ 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_struct *png_ptr)
+{
+ /* write the crc */
+ png_write_uint_32(png_ptr, ~png_ptr->crc);
+}
+
+/* simple function to write the signature */
+void
+png_write_sig(png_struct *png_ptr)
+{
+ /* write the 8 byte signature */
+ png_write_data(png_ptr, png_sig, (png_uint_32)8);
+}
+
+/* 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_struct *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 */
+
+ /* pack the header information into the buffer */
+ png_save_uint_32(buf, width);
+ png_save_uint_32(buf + 4, height);
+ buf[8] = bit_depth;
+ buf[9] = color_type;
+ buf[10] = compression_type;
+ buf[11] = filter_type;
+ buf[12] = interlace_type;
+ /* save off the relevent information */
+ png_ptr->bit_depth = bit_depth;
+ png_ptr->color_type = color_type;
+ png_ptr->interlaced = interlace_type;
+ png_ptr->width = width;
+ png_ptr->height = height;
+
+ switch (color_type)
+ {
+ case 0:
+ case 3:
+ png_ptr->channels = 1;
+ break;
+ case 2:
+ png_ptr->channels = 3;
+ break;
+ case 4:
+ png_ptr->channels = 2;
+ break;
+ case 6:
+ png_ptr->channels = 4;
+ break;
+ }
+ png_ptr->pixel_depth = bit_depth * png_ptr->channels;
+ png_ptr->rowbytes = ((width * (png_uint_32)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;
+
+ /* write the chunk */
+ png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13);
+}
+
+/* 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 convient
+ structure. */
+void
+png_write_PLTE(png_struct *png_ptr, png_color *palette, int number)
+{
+ int i;
+ png_color *pal_ptr;
+ png_byte buf[3];
+
+ png_write_chunk_start(png_ptr, png_PLTE, number * 3);
+ for (i = 0, pal_ptr = palette;
+ i < number;
+ 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_uint_32)3);
+ }
+ png_write_chunk_end(png_ptr);
+}
+
+/* write an IDAT chunk */
+void
+png_write_IDAT(png_struct *png_ptr, png_byte *data, png_uint_32 length)
+{
+#ifdef zlibinout
+/* temp zlib problem */
+{
+ extern FILE *fpzlibout;
+
+ fwrite(data, 1, length, fpzlibout);
+}
+/* end temp zlib problem */
+#endif
+
+ png_write_chunk(png_ptr, png_IDAT, data, length);
+}
+
+/* write an IEND chunk */
+void
+png_write_IEND(png_struct *png_ptr)
+{
+ png_write_chunk(png_ptr, png_IEND, NULL, (png_uint_32)0);
+}
+
+/* write a gAMA chunk */
+void
+png_write_gAMA(png_struct *png_ptr, float gamma)
+{
+ png_uint_32 igamma;
+ png_byte buf[4];
+
+ /* gamma is saved in 1/100,000ths */
+ igamma = (png_uint_32)(gamma * 100000.0 + 0.5);
+ png_save_uint_32(buf, igamma);
+ png_write_chunk(png_ptr, png_gAMA, buf, (png_uint_32)4);
+}
+
+/* write the sBIT chunk */
+void
+png_write_sBIT(png_struct *png_ptr, png_color_8 *sbit, int color_type)
+{
+ png_byte buf[4];
+ int size;
+
+ /* make sure we don't depend upon the order of png_color_8 */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ buf[0] = sbit->red;
+ buf[1] = sbit->green;
+ buf[2] = sbit->blue;
+ size = 3;
+ }
+ else
+ {
+ buf[0] = sbit->gray;
+ size = 1;
+ }
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ buf[size++] = sbit->alpha;
+ }
+
+ png_write_chunk(png_ptr, png_sBIT, buf, (png_uint_32)size);
+}
+
+/* write the cHRM chunk */
+void
+png_write_cHRM(png_struct *png_ptr, float white_x, float white_y,
+ float red_x, float red_y, float green_x, float green_y,
+ float blue_x, float blue_y)
+{
+ png_uint_32 itemp;
+ png_byte buf[32];
+
+ /* each value is saved int 1/100,000ths */
+ 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);
+ 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);
+ 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);
+ 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_uint_32)32);
+}
+
+/* write the tRNS chunk */
+void
+png_write_tRNS(png_struct *png_ptr, png_byte *trans, png_color_16 *tran,
+ int num_trans, int color_type)
+{
+ png_byte buf[6];
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ /* write the chunk out as it is */
+ png_write_chunk(png_ptr, png_tRNS, trans, (png_uint_32)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_uint_32)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_uint_32)6);
+ }
+}
+
+/* write the background chunk */
+void
+png_write_bKGD(png_struct *png_ptr, png_color_16 *back, int color_type)
+{
+ png_byte buf[6];
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ buf[0] = back->index;
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)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_uint_32)6);
+ }
+ else
+ {
+ png_save_uint_16(buf, back->gray);
+ png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)2);
+ }
+}
+
+/* write the histogram */
+void
+png_write_hIST(png_struct *png_ptr, png_uint_16 *hist, int number)
+{
+ int i;
+ png_byte buf[3];
+
+ png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(number * 2));
+ for (i = 0; i < number; i++)
+ {
+ png_save_uint_16(buf, hist[i]);
+ png_write_chunk_data(png_ptr, buf, (png_uint_32)2);
+ }
+ png_write_chunk_end(png_ptr);
+}
+
+/* write a tEXt chunk */
+void
+png_write_tEXt(png_struct *png_ptr, char *key, char *text,
+ png_uint_32 text_len)
+{
+ int key_len;
+
+ key_len = strlen(key);
+ /* make sure we count the 0 after the key */
+ png_write_chunk_start(png_ptr, png_tEXt,
+ (png_uint_32)(key_len + text_len + 1));
+ /* key has an 0 at the end. How nice */
+ png_write_chunk_data(png_ptr, (png_byte *)key, (png_uint_32)(key_len + 1));
+ if (text && text_len)
+ png_write_chunk_data(png_ptr, (png_byte *)text, (png_uint_32)text_len);
+ png_write_chunk_end(png_ptr);
+}
+
+/* write a compressed chunk */
+void
+png_write_zTXt(png_struct *png_ptr, char *key, char *text,
+ png_uint_32 text_len, int compression)
+{
+ int key_len;
+ char buf[1];
+ int i, ret;
+ char **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 */
+
+ key_len = strlen(key);
+
+ /* we can't write the chunk until we find out how much data we have,
+ which means we need to run the compresser 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
+ malloced pointers to be sure. */
+
+ /* set up the compression buffers */
+ png_ptr->zstream->avail_in = (uInt)text_len;
+ png_ptr->zstream->next_in = (Byte *)text;
+ png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream->next_out = (Byte *)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)
+ 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)
+ {
+ max_output_ptr = num_output_ptr + 4;
+ if (output_ptr)
+ output_ptr = png_realloc(png_ptr, output_ptr,
+ max_output_ptr * sizeof (char *));
+ else
+ output_ptr = png_malloc(png_ptr,
+ max_output_ptr * sizeof (char *));
+ }
+
+ /* save the data */
+ output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
+ png_ptr->zbuf_size);
+ memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
+ (png_size_t)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 anymore 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)
+ 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)
+ {
+ max_output_ptr = num_output_ptr + 4;
+ if (output_ptr)
+ output_ptr = png_realloc(png_ptr, output_ptr,
+ max_output_ptr * sizeof (char *));
+ else
+ output_ptr = png_malloc(png_ptr,
+ max_output_ptr * sizeof (char *));
+ }
+
+ /* save off the data */
+ output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
+ png_ptr->zbuf_size);
+ memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
+ (png_size_t)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_uint_32)(png_ptr->zbuf_size -
+ 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_byte *)key, (png_uint_32)(key_len + 1));
+ buf[0] = compression;
+ /* write compression */
+ png_write_chunk_data(png_ptr, (png_byte *)buf, (png_uint_32)1);
+
+ /* write saved output buffers, if any */
+ for (i = 0; i < num_output_ptr; i++)
+ {
+ png_write_chunk_data(png_ptr, (png_byte *)output_ptr[i], png_ptr->zbuf_size);
+ png_large_free(png_ptr, output_ptr[i]);
+ }
+ if (max_output_ptr)
+ png_free(png_ptr, output_ptr);
+ /* write anything left in zbuf */
+ if (png_ptr->zstream->avail_out < 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); */
+ deflateEnd(png_ptr->zstream);
+ deflateInit(png_ptr->zstream, -1);
+}
+
+/* write the pHYs chunk */
+void
+png_write_pHYs(png_struct *png_ptr, png_uint_32 x_pixels_per_unit,
+ png_uint_32 y_pixels_per_unit,
+ int unit_type)
+{
+ png_byte buf[9];
+
+ png_save_uint_32(buf, x_pixels_per_unit);
+ png_save_uint_32(buf + 4, y_pixels_per_unit);
+ buf[8] = unit_type;
+
+ png_write_chunk(png_ptr, png_pHYs, buf, (png_uint_32)9);
+}
+
+/* write the oFFs chunk */
+void
+png_write_oFFs(png_struct *png_ptr, png_uint_32 x_offset,
+ png_uint_32 y_offset,
+ int unit_type)
+{
+ png_byte buf[9];
+
+ png_save_uint_32(buf, x_offset);
+ png_save_uint_32(buf + 4, y_offset);
+ buf[8] = unit_type;
+
+ png_write_chunk(png_ptr, png_oFFs, buf, (png_uint_32)9);
+}
+
+/* two time chunks are given. This chunk assumes you have a gmtime()
+ function. If you don't have that, use the other tIME function */
+void
+png_write_tIME(png_struct *png_ptr, png_time *mod_time)
+{
+ png_byte buf[7];
+
+ 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_uint_32)7);
+}
+
+/* initializes the row writing capability of libpng */
+void
+png_write_start_row(png_struct *png_ptr)
+{
+ /* set up row buffer */
+ png_ptr->row_buf = (png_byte *)png_large_malloc(png_ptr,
+ (((png_uint_32)png_ptr->usr_channels *
+ (png_uint_32)png_ptr->usr_bit_depth *
+ png_ptr->width) >> 3) + 1);
+ /* set up filtering buffers, if filtering */
+ if (png_ptr->bit_depth >= 8 && png_ptr->color_type != 3)
+ {
+ png_ptr->prev_row = (png_byte *)png_large_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
+ png_ptr->save_row = (png_byte *)png_large_malloc(png_ptr,
+ png_ptr->rowbytes + 1);
+ memset(png_ptr->save_row, 0, (png_size_t)png_ptr->rowbytes + 1);
+ }
+
+ /* 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
+ {
+ 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_struct *png_ptr)
+{
+ int ret;
+
+ /* next row */
+ png_ptr->row_number++;
+ /* see if we are done */
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ /* 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];
+ } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
+
+ }
+
+ /* reset filter row */
+ if (png_ptr->prev_row)
+ memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1);
+ /* if we have more data to get, go get it */
+ if (png_ptr->pass < 7)
+ return;
+ }
+
+ /* 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)
+ 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); */
+ deflateEnd(png_ptr->zstream);
+ deflateInit(png_ptr->zstream, -1);
+
+}
+
+/* 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_info *row_info, png_byte *row, int pass)
+{
+ /* we don't have to do anything on the last pass (6) */
+ if (row && row_info && pass < 6)
+ {
+ /* each pixel depth is handled seperately */
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+
+ dp = row;
+ d = 0;
+ shift = 7;
+ for (i = png_pass_start[pass];
+ i < row_info->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++ = d;
+ d = 0;
+ }
+ else
+ shift--;
+
+ }
+ if (shift != 7)
+ *dp = d;
+ break;
+ }
+ case 2:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+
+ dp = row;
+ shift = 6;
+ d = 0;
+ for (i = png_pass_start[pass];
+ i < row_info->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++ = d;
+ d = 0;
+ }
+ else
+ shift -= 2;
+ }
+ if (shift != 6)
+ *dp = d;
+ break;
+ }
+ case 4:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+
+ dp = row;
+ shift = 4;
+ d = 0;
+ for (i = png_pass_start[pass];
+ i < row_info->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++ = d;
+ d = 0;
+ }
+ else
+ shift -= 4;
+ }
+ if (shift != 4)
+ *dp = d;
+ break;
+ }
+ default:
+ {
+ png_byte *sp;
+ png_byte *dp;
+ png_uint_32 i;
+ int 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_info->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)
+ 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);
+
+ }
+}
+
+/* this filters the row. Both row and prev_row have space at the
+ first byte for the filter byte. */
+void
+png_write_filter_row(png_row_info *row_info, png_byte *row,
+ png_byte *prev_row)
+{
+ int minf, bpp;
+ png_uint_32 i, v;
+ png_uint_32 s, mins;
+ png_byte *rp, *pp, *cp, *lp;
+
+ /* find out how many bytes offset each pixel is */
+ bpp = (row_info->pixel_depth + 7) / 8;
+ if (bpp < 1)
+ bpp = 1;
+
+ /* the prediction method we use is to find which method provides
+ the smallest value when summing the abs of the distances from
+ zero using anything >= 128 as negitive numbers. */
+ for (i = 0, s = 0, rp = row + 1; i < row_info->rowbytes; i++, rp++)
+ {
+ v = *rp;
+ if (v < 128)
+ s += v;
+ else
+ s += 256 - (png_int_32)v;
+ }
+
+ mins = s;
+ minf = 0;
+
+ /* check sub filter */
+ for (i = 0, s = 0, rp = row + 1, lp = row + 1 - bpp;
+ i < row_info->rowbytes; i++, rp++, lp++)
+ {
+ if (i >= bpp)
+ v = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+ else
+ v = *rp;
+
+ if (v < 128)
+ s += v;
+ else
+ s += 256 - v;
+ }
+
+ if (s < mins)
+ {
+ mins = s;
+ minf = 1;
+ }
+
+ /* check up filter */
+ for (i = 0, s = 0, rp = row + 1, pp = prev_row + 1;
+ i < row_info->rowbytes; i++, rp++, pp++)
+ {
+ v = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+
+ if (v < 128)
+ s += v;
+ else
+ s += 256 - v;
+ }
+
+ if (s < mins)
+ {
+ mins = s;
+ minf = 2;
+ }
+
+ /* check avg filter */
+ for (i = 0, s = 0, rp = row + 1, pp = prev_row + 1, lp = row + 1 - bpp;
+ i < row_info->rowbytes; i++, rp++, pp++, lp++)
+ {
+ if (i >= bpp)
+ v = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
+ else
+ v = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
+
+ if (v < 128)
+ s += v;
+ else
+ s += 256 - v;
+ }
+
+ if (s < mins)
+ {
+ mins = s;
+ minf = 3;
+ }
+
+ /* check paeth filter */
+ for (i = 0, s = 0, rp = row + 1, pp = prev_row + 1, lp = row + 1 - bpp,
+ cp = prev_row + 1 - bpp;
+ i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp;
+ if (i >= bpp)
+ {
+ c = *cp;
+ a = *lp;
+ }
+ else
+ {
+ a = c = 0;
+ }
+ 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;
+
+ v = (png_byte)(((int)*rp - p) & 0xff);
+
+ if (v < 128)
+ s += v;
+ else
+ s += 256 - v;
+ }
+
+ if (s < mins)
+ {
+ mins = s;
+ minf = 4;
+ }
+
+ /* set filter byte */
+ row[0] = minf;
+
+ /* do filter */
+ switch (minf)
+ {
+ /* sub filter */
+ case 1:
+ for (i = bpp, rp = row + (png_size_t)row_info->rowbytes,
+ lp = row + (png_size_t)row_info->rowbytes - bpp;
+ i < row_info->rowbytes; i++, rp--, lp--)
+ {
+ *rp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+ }
+ break;
+ /* up filter */
+ case 2:
+ for (i = 0, rp = row + (png_size_t)row_info->rowbytes,
+ pp = prev_row + (png_size_t)row_info->rowbytes;
+ i < row_info->rowbytes; i++, rp--, pp--)
+ {
+ *rp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+ }
+ break;
+ /* avg filter */
+ case 3:
+ for (i = row_info->rowbytes,
+ rp = row + (png_size_t)row_info->rowbytes,
+ pp = prev_row + (png_size_t)row_info->rowbytes,
+ lp = row + (png_size_t)row_info->rowbytes - bpp;
+ i > bpp; i--, rp--, lp--, pp--)
+ {
+ *rp = (png_byte)(((int)*rp - (((int)*lp + (int)*pp) /
+ 2)) & 0xff);
+ }
+ for (; i > 0; i--, rp--, pp--)
+ {
+ *rp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
+ }
+ break;
+ /* paeth filter */
+ case 4:
+ for (i = row_info->rowbytes,
+ rp = row + (png_size_t)row_info->rowbytes,
+ pp = prev_row + (png_size_t)row_info->rowbytes,
+ lp = row + (png_size_t)row_info->rowbytes - bpp,
+ cp = prev_row + (png_size_t)row_info->rowbytes - bpp;
+ i > 0; i--, rp--, lp--, pp--, cp--)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp;
+ if (i > bpp)
+ {
+ c = *cp;
+ a = *lp;
+ }
+ else
+ {
+ a = c = 0;
+ }
+ 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;
+
+ *rp = (png_byte)(((int)*rp - p) & 0xff);
+ }
+ break;
+ }
+}
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 000000000..3ca55c55b
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,79 @@
+readme.txt - for libpng 0.71
+
+This is the first beta version of libpng 1.0. By beta, I mean that
+all the code for 1.0 is there, and it works on all the machines
+I have running all the tests I have devised. However, there is
+always one more bug (at least), and I don't have many #define's in
+the code (yet) for various platforms that I do not have. Also, I'd
+like to see if I can get the code to compile with as few warnings
+as possible. Finally, as people use my code, they may have
+suggestions for additions that will make pnglib easier to port.
+
+For a detailed description on using libpng, read libpng.txt. 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 make file, but you will probably have to modify it
+for your own needs. I'm using Borland C++, running large memory
+model on Windows 3.11, but it should work on almost anything. Support
+for medium memory model is planned, but is not in 1.0 (probably in 1.1).
+
+You will need zlib 0.93 to run this. zlib is a compression
+library that is useful for more things then just png files. If
+you need a compression library, check out zlib.h
+
+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 will also want a copy of the PNG specification. It should
+be available at the same place you picked up libpng. If it is
+not there, 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 at ftp.group42.com in the /pub/png
+directory, and on CompuServe, Lib 20 (PNG) at GO GRAPHSUP.
+If you can't find it in any of those places, e-mail me, and I'll
+tell you where it is.
+
+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.
+
+You can reach me at:
+
+internet: schalnat&group42.com
+CompuServe: 75501,1625
+
+Please do not send me general questions about PNG. Send them to
+the address in the specification. At the same time, please do
+not send libpng questions to that address, send them to me. 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 6 months 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.
+
+Good luck, and happy coding.
+
+-Guy Eric Schalnat
+ Group 42, Inc.
+ Internet: schalnat@group42.com
+ CompuServe: 75501,1625
+ Web: www.group42.com
+ FTP: ftp.group42.com
+