aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:05 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:05 -0800
commit893912bfc2683463dc3e2c445336752d012563d3 (patch)
treed69220fafcd6687fe39ca99ad8c74820b429d6a9 /contrib
parent0d889b4fd2c96153983a28cc5757c0172d9eb78b (diff)
downloadexternal_libpng-893912bfc2683463dc3e2c445336752d012563d3.zip
external_libpng-893912bfc2683463dc3e2c445336752d012563d3.tar.gz
external_libpng-893912bfc2683463dc3e2c445336752d012563d3.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'contrib')
-rw-r--r--contrib/gregbook/COPYING340
-rw-r--r--contrib/gregbook/LICENSE50
-rw-r--r--contrib/gregbook/Makefile.mingw32130
-rw-r--r--contrib/gregbook/Makefile.sgi104
-rw-r--r--contrib/gregbook/Makefile.unx132
-rw-r--r--contrib/gregbook/Makefile.w32113
-rw-r--r--contrib/gregbook/README186
-rw-r--r--contrib/gregbook/makevms.com132
-rw-r--r--contrib/gregbook/readpng.c304
-rw-r--r--contrib/gregbook/readpng.h88
-rw-r--r--contrib/gregbook/readpng2.c645
-rw-r--r--contrib/gregbook/readpng2.h121
-rw-r--r--contrib/gregbook/readppm.c179
-rw-r--r--contrib/gregbook/rpng-win.c684
-rw-r--r--contrib/gregbook/rpng-x.c904
-rw-r--r--contrib/gregbook/rpng2-win.c1225
-rw-r--r--contrib/gregbook/rpng2-x.c2127
-rw-r--r--contrib/gregbook/toucan.pngbin0 -> 12901 bytes
-rw-r--r--contrib/gregbook/wpng.c853
-rw-r--r--contrib/gregbook/writepng.c392
-rw-r--r--contrib/gregbook/writepng.h133
-rw-r--r--contrib/pngminim/decoder/README6
-rwxr-xr-xcontrib/pngminim/decoder/gather.sh8
-rw-r--r--contrib/pngminim/decoder/makefile.std44
-rw-r--r--contrib/pngminim/decoder/pngusr.h67
-rw-r--r--contrib/pngminim/encoder/README6
-rw-r--r--contrib/pngminim/encoder/dummy_inflate.c27
-rwxr-xr-xcontrib/pngminim/encoder/gather.sh9
-rw-r--r--contrib/pngminim/encoder/makefile.std43
-rw-r--r--contrib/pngminim/encoder/pngusr.h66
-rw-r--r--contrib/pngminus/README153
-rw-r--r--contrib/pngminus/makefile.std65
-rw-r--r--contrib/pngminus/makefile.tc338
-rw-r--r--contrib/pngminus/makevms.com92
-rw-r--r--contrib/pngminus/png2pnm.bat41
-rw-r--r--contrib/pngminus/png2pnm.c430
-rw-r--r--contrib/pngminus/png2pnm.sh42
-rw-r--r--contrib/pngminus/pngminus.bat4
-rw-r--r--contrib/pngminus/pngminus.sh5
-rw-r--r--contrib/pngminus/pnm2png.bat41
-rw-r--r--contrib/pngminus/pnm2png.c533
-rw-r--r--contrib/pngminus/pnm2png.sh42
-rw-r--r--contrib/pngsuite/README85
-rw-r--r--contrib/pngsuite/basn0g01.pngbin0 -> 164 bytes
-rw-r--r--contrib/pngsuite/basn0g02.pngbin0 -> 104 bytes
-rw-r--r--contrib/pngsuite/basn0g04.pngbin0 -> 145 bytes
-rw-r--r--contrib/pngsuite/basn0g08.pngbin0 -> 138 bytes
-rw-r--r--contrib/pngsuite/basn0g16.pngbin0 -> 167 bytes
-rw-r--r--contrib/pngsuite/basn2c08.pngbin0 -> 145 bytes
-rw-r--r--contrib/pngsuite/basn2c16.pngbin0 -> 302 bytes
-rw-r--r--contrib/pngsuite/basn3p01.pngbin0 -> 112 bytes
-rw-r--r--contrib/pngsuite/basn3p02.pngbin0 -> 146 bytes
-rw-r--r--contrib/pngsuite/basn3p04.pngbin0 -> 216 bytes
-rw-r--r--contrib/pngsuite/basn3p08.pngbin0 -> 1286 bytes
-rw-r--r--contrib/pngsuite/basn4a08.pngbin0 -> 126 bytes
-rw-r--r--contrib/pngsuite/basn4a16.pngbin0 -> 2206 bytes
-rw-r--r--contrib/pngsuite/basn6a08.pngbin0 -> 184 bytes
-rw-r--r--contrib/pngsuite/basn6a16.pngbin0 -> 3435 bytes
-rw-r--r--contrib/visupng/PngFile.c439
-rw-r--r--contrib/visupng/PngFile.h27
-rw-r--r--contrib/visupng/README.txt58
-rw-r--r--contrib/visupng/VisualPng.c961
-rw-r--r--contrib/visupng/VisualPng.dsp147
-rw-r--r--contrib/visupng/VisualPng.dsw29
-rw-r--r--contrib/visupng/VisualPng.icobin0 -> 766 bytes
-rw-r--r--contrib/visupng/VisualPng.pngbin0 -> 208 bytes
-rw-r--r--contrib/visupng/VisualPng.rc152
-rw-r--r--contrib/visupng/cexcept.h243
-rw-r--r--contrib/visupng/resource.h23
69 files changed, 12768 insertions, 0 deletions
diff --git a/contrib/gregbook/COPYING b/contrib/gregbook/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/contrib/gregbook/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, 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 show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 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 Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision 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 generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/gregbook/LICENSE b/contrib/gregbook/LICENSE
new file mode 100644
index 0000000..d956717
--- /dev/null
+++ b/contrib/gregbook/LICENSE
@@ -0,0 +1,50 @@
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------
diff --git a/contrib/gregbook/Makefile.mingw32 b/contrib/gregbook/Makefile.mingw32
new file mode 100644
index 0000000..e70a59a
--- /dev/null
+++ b/contrib/gregbook/Makefile.mingw32
@@ -0,0 +1,130 @@
+# Sample makefile for rpng-win / rpng2-win / wpng using mingw32-gcc and make.
+# Greg Roelofs
+# Last modified: 2 June 2007
+#
+# The programs built by this makefile are described in the book,
+# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and
+# Associates, 1999). Go buy a copy, eh? Well, OK, it's not
+# generally for sale anymore, but it's the thought that counts,
+# right? (Hint: http://www.libpng.org/pub/png/book/ )
+#
+# Invoke this makefile from a DOS-prompt window via:
+#
+# make -f Makefile.mingw32
+#
+# This makefile assumes libpng and zlib have already been built or downloaded
+# and are in subdirectories at the same level as the current subdirectory
+# (as indicated by the PNGDIR and ZDIR macros below). It makes no assumptions
+# at all about the mingw32 installation tree (W32DIR). Edit as appropriate.
+#
+# Note that the names of the dynamic and static libpng and zlib libraries
+# used below may change in later releases of the libraries. This makefile
+# builds both statically and dynamically linked executables by default.
+# (You need only one set, but for testing it can be handy to have both.)
+
+
+# macros --------------------------------------------------------------------
+
+#PNGDIR = ../..# for libpng-x.y.z/contrib/gregbook builds
+PNGDIR = ../libpng-win32
+PNGINC = -I$(PNGDIR)
+PNGLIBd = $(PNGDIR)/libpng.dll.a # dynamically linked
+PNGLIBs = $(PNGDIR)/libpng.a # statically linked, local libpng
+
+#ZDIR = ../../../zlib-win32# for libpng-x.y.z/contrib/gregbook builds
+ZDIR = ../zlib-win32
+ZINC = -I$(ZDIR)
+ZLIBd = $(ZDIR)/libzdll.a
+ZLIBs = $(ZDIR)/libz.a
+
+# change this to be the path where mingw32 installs its stuff:
+W32DIR =
+#W32DIR = /usr/local/cross-tools/i386-mingw32msvc
+W32INC = -I$(W32DIR)/include
+W32LIB = $(W32DIR)/lib/libuser32.a $(W32DIR)/lib/libgdi32.a
+
+CC = gcc
+#CC = i386-mingw32msvc-gcc # e.g., Linux -> Win32 cross-compilation
+LD = $(CC)
+RM = rm -f
+CFLAGS = -O -Wall $(INCS) $(MINGW_CCFLAGS)
+# [note that -Wall is a gcc-specific compilation flag ("most warnings on")]
+# [-ansi, -pedantic and -W can also be used]
+LDFLAGS = $(MINGW_LDFLAGS)
+O = .o
+E = .exe
+
+INCS = $(PNGINC) $(ZINC) $(W32INC)
+RLIBSd = $(PNGLIBd) $(ZLIBd) $(W32LIB) -lm
+RLIBSs = $(PNGLIBs) $(ZLIBs) $(W32LIB) -lm
+WLIBSd = $(PNGLIBd) $(ZLIBd)
+WLIBSs = $(PNGLIBs) $(ZLIBs)
+
+RPNG = rpng-win
+RPNG2 = rpng2-win
+WPNG = wpng
+
+ROBJSd = $(RPNG)$(O) readpng.pic$(O)
+ROBJS2d = $(RPNG2)$(O) readpng2.pic$(O)
+WOBJSd = $(WPNG)$(O) writepng.pic$(O)
+
+RPNGs = $(RPNG)-static
+RPNG2s = $(RPNG2)-static
+WPNGs = $(WPNG)-static
+
+ROBJSs = $(RPNG)$(O) readpng$(O)
+ROBJS2s = $(RPNG2)$(O) readpng2$(O)
+WOBJSs = $(WPNG)$(O) writepng$(O)
+
+STATIC_EXES = $(RPNGs)$(E) $(RPNG2s)$(E) $(WPNGs)$(E)
+DYNAMIC_EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E)
+
+EXES = $(STATIC_EXES) $(DYNAMIC_EXES)
+
+
+# implicit make rules -------------------------------------------------------
+
+.c$(O):
+ $(CC) -c $(CFLAGS) $<
+
+%.pic$(O): %.c
+ $(CC) -c $(CFLAGS) -DPNG_BUILD_DLL -o $@ $<
+
+
+# dependencies --------------------------------------------------------------
+
+all: $(EXES)
+
+$(RPNGs)$(E): $(ROBJSs)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJSs) $(RLIBSs)
+
+$(RPNG)$(E): $(ROBJSd)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJSd) $(RLIBSd)
+
+$(RPNG2s)$(E): $(ROBJS2s)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS2s) $(RLIBSs)
+
+$(RPNG2)$(E): $(ROBJS2d)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS2d) $(RLIBSd)
+
+$(WPNGs)$(E): $(WOBJSs)
+ $(LD) $(LDFLAGS) -o $@ $(WOBJSs) $(WLIBSs)
+
+$(WPNG)$(E): $(WOBJSd)
+ $(LD) $(LDFLAGS) -o $@ $(WOBJSd) $(WLIBSd)
+
+$(RPNG)$(O): $(RPNG).c readpng.h
+$(RPNG2)$(O): $(RPNG2).c readpng2.h
+$(WPNG)$(O): $(WPNG).c writepng.h
+
+readpng$(O) readpng.pic$(O): readpng.c readpng.h
+readpng2$(O) readpng2.pic$(O): readpng2.c readpng2.h
+writepng$(O) writepng.pic$(O): writepng.c writepng.h
+
+
+# maintenance ---------------------------------------------------------------
+
+clean:
+ $(RM) $(EXES)
+ $(RM) $(ROBJSs) $(ROBJS2s) $(WOBJSs)
+ $(RM) $(ROBJSd) $(ROBJS2d) $(WOBJSd)
diff --git a/contrib/gregbook/Makefile.sgi b/contrib/gregbook/Makefile.sgi
new file mode 100644
index 0000000..e3ca6ce
--- /dev/null
+++ b/contrib/gregbook/Makefile.sgi
@@ -0,0 +1,104 @@
+# Sample makefile for rpng-x / rpng2-x / wpng for SGI using cc and make.
+# Greg Roelofs
+# Last modified: 7 March 2002
+#
+# The programs built by this makefile are described in the book,
+# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and
+# Associates, 1999). Go buy a copy, eh? Buy some for friends
+# and family, too. (Not that this is a blatant plug or anything.)
+#
+# Invoke this makefile from a shell prompt in the usual way; for example:
+#
+# make -f Makefile.sgi
+#
+# This makefile assumes libpng and zlib have already been built or downloaded
+# and are both installed in /usr/local/{include,lib} (as indicated by the
+# PNG* and Z* macros below). Edit as appropriate--choose only ONE each of
+# the PNGINC, PNGLIB, ZINC and ZLIB lines.
+#
+# This makefile builds dynamically linked executables (against libpng and zlib,
+# that is), but that can be changed by uncommenting the appropriate PNGLIB and
+# ZLIB lines.
+
+
+# macros --------------------------------------------------------------------
+
+PNGINC = -I/usr/local/include/libpng12
+PNGLIB = -L/usr/local/lib -lpng12 # dynamically linked against libpng
+#PNGLIB = /usr/local/lib/libpng12.a # statically linked against libpng
+# or:
+#PNGINC = -I../..
+#PNGLIB = -L../.. -lpng
+#PNGLIB = ../../libpng.a
+
+ZINC = -I/usr/local/include
+ZLIB = -L/usr/local/lib -lz # dynamically linked against zlib
+#ZLIB = /usr/local/lib/libz.a # statically linked against zlib
+#ZINC = -I../zlib
+#ZLIB = -L../zlib -lz
+#ZLIB = ../../../zlib/libz.a
+
+XINC = -I/usr/include/X11 # old-style, stock X distributions
+XLIB = -L/usr/lib/X11 -lX11
+#XINC = -I/usr/openwin/include # Sun workstations (OpenWindows)
+#XLIB = -L/usr/openwin/lib -lX11
+#XINC = -I/usr/X11R6/include # new X distributions (XFree86, etc.)
+#XLIB = -L/usr/X11R6/lib -lX11
+
+INCS = $(PNGINC) $(ZINC) $(XINC)
+RLIBS = $(PNGLIB) $(ZLIB) $(XLIB) -lm
+WLIBS = $(PNGLIB) $(ZLIB)
+
+CC = cc
+LD = cc
+RM = rm -f
+# ABI must be the same as that used to build libpng.
+ABI=
+CFLAGS = $(ABI) -O -fullwarn $(INCS)
+LDFLAGS = $(ABI)
+O = .o
+E =
+
+RPNG = rpng-x
+RPNG2 = rpng2-x
+WPNG = wpng
+
+ROBJS = $(RPNG)$(O) readpng$(O)
+ROBJS2 = $(RPNG2)$(O) readpng2$(O)
+WOBJS = $(WPNG)$(O) writepng$(O)
+
+EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E)
+
+
+# implicit make rules -------------------------------------------------------
+
+.c$(O):
+ $(CC) -c $(CFLAGS) $<
+
+
+# dependencies --------------------------------------------------------------
+
+all: $(EXES)
+
+$(RPNG)$(E): $(ROBJS)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBS)
+
+$(RPNG2)$(E): $(ROBJS2)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBS)
+
+$(WPNG)$(E): $(WOBJS)
+ $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBS)
+
+$(RPNG)$(O): $(RPNG).c readpng.h
+$(RPNG2)$(O): $(RPNG2).c readpng2.h
+$(WPNG)$(O): $(WPNG).c writepng.h
+
+readpng$(O): readpng.c readpng.h
+readpng2$(O): readpng2.c readpng2.h
+writepng$(O): writepng.c writepng.h
+
+
+# maintenance ---------------------------------------------------------------
+
+clean:
+ $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS)
diff --git a/contrib/gregbook/Makefile.unx b/contrib/gregbook/Makefile.unx
new file mode 100644
index 0000000..7ff65bf
--- /dev/null
+++ b/contrib/gregbook/Makefile.unx
@@ -0,0 +1,132 @@
+# Sample makefile for rpng-x / rpng2-x / wpng using gcc and make.
+# Greg Roelofs
+# Last modified: 2 June 2007
+#
+# The programs built by this makefile are described in the book,
+# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and
+# Associates, 1999). Go buy a copy, eh? Well, OK, it's not
+# generally for sale anymore, but it's the thought that counts,
+# right? (Hint: http://www.libpng.org/pub/png/book/ )
+#
+# Invoke this makefile from a shell prompt in the usual way; for example:
+#
+# make -f Makefile.unx
+#
+# This makefile assumes libpng and zlib have already been built or downloaded
+# and are installed in /usr/local/{include,lib} or as otherwise indicated by
+# the PNG* and Z* macros below. Edit as appropriate--choose only ONE each of
+# the PNGINC, PNGLIBd, PNGLIBs, ZINC, ZLIBd and ZLIBs lines.
+#
+# This makefile builds both dynamically and statically linked executables
+# (against libpng and zlib, that is), but that can be changed by modifying
+# the "EXES =" line. (You need only one set, but for testing it can be handy
+# to have both.)
+
+
+# macros --------------------------------------------------------------------
+
+#PNGDIR = /usr/local/lib
+#PNGINC = -I/usr/local/include/libpng12
+#PNGLIBd = -L$(PNGDIR) -lpng12 # dynamically linked, installed libpng
+#PNGLIBs = $(PNGDIR)/libpng12.a # statically linked, installed libpng
+# or:
+PNGDIR = ../..# this one is for libpng-x.y.z/contrib/gregbook builds
+#PNGDIR = ../libpng
+PNGINC = -I$(PNGDIR)
+PNGLIBd = -Wl,-rpath,$(PNGDIR) -L$(PNGDIR) -lpng12 # dynamically linked
+PNGLIBs = $(PNGDIR)/libpng.a # statically linked, local libpng
+
+ZDIR = /usr/local/lib
+#ZDIR = /usr/lib64
+ZINC = -I/usr/local/include
+ZLIBd = -L$(ZDIR) -lz # dynamically linked against zlib
+ZLIBs = $(ZDIR)/libz.a # statically linked against zlib
+# or:
+#ZDIR = ../zlib
+#ZINC = -I$(ZDIR)
+#ZLIBd = -Wl,-rpath,$(ZDIR) -L$(ZDIR) -lz # -rpath allows in-place testing
+#ZLIBs = $(ZDIR)/libz.a
+
+#XINC = -I/usr/include # old-style, stock X distributions
+#XLIB = -L/usr/lib/X11 -lX11 # (including SGI IRIX)
+#XINC = -I/usr/openwin/include # Sun workstations (OpenWindows)
+#XLIB = -L/usr/openwin/lib -lX11
+XINC = -I/usr/X11R6/include # new X distributions (X.org, etc.)
+XLIB = -L/usr/X11R6/lib -lX11
+#XLIB = -L/usr/X11R6/lib64 -lX11 # e.g., Red Hat on AMD64
+
+INCS = $(PNGINC) $(ZINC) $(XINC)
+RLIBSd = $(PNGLIBd) $(ZLIBd) $(XLIB) -lm
+RLIBSs = $(PNGLIBs) $(ZLIBs) $(XLIB) -lm
+WLIBSd = $(PNGLIBd) $(ZLIBd) -lm
+WLIBSs = $(PNGLIBs) $(ZLIBs)
+
+CC = gcc
+LD = gcc
+RM = rm -f
+CFLAGS = -O -Wall $(INCS) -DFEATURE_LOOP
+# [note that -Wall is a gcc-specific compilation flag ("most warnings on")]
+# [-ansi, -pedantic and -W can also be used]
+LDFLAGS =
+O = .o
+E =
+
+RPNG = rpng-x
+RPNG2 = rpng2-x
+WPNG = wpng
+
+RPNGs = $(RPNG)-static
+RPNG2s = $(RPNG2)-static
+WPNGs = $(WPNG)-static
+
+ROBJS = $(RPNG)$(O) readpng$(O)
+ROBJS2 = $(RPNG2)$(O) readpng2$(O)
+WOBJS = $(WPNG)$(O) writepng$(O)
+
+STATIC_EXES = $(RPNGs)$(E) $(RPNG2s)$(E) $(WPNGs)$(E)
+DYNAMIC_EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E)
+
+EXES = $(STATIC_EXES) $(DYNAMIC_EXES)
+
+
+# implicit make rules -------------------------------------------------------
+
+.c$(O):
+ $(CC) -c $(CFLAGS) $<
+
+
+# dependencies --------------------------------------------------------------
+
+all: $(EXES)
+
+$(RPNGs)$(E): $(ROBJS)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBSs)
+
+$(RPNG)$(E): $(ROBJS)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS) $(RLIBSd)
+
+$(RPNG2s)$(E): $(ROBJS2)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBSs)
+
+$(RPNG2)$(E): $(ROBJS2)
+ $(LD) $(LDFLAGS) -o $@ $(ROBJS2) $(RLIBSd)
+
+$(WPNGs)$(E): $(WOBJS)
+ $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBSs)
+
+$(WPNG)$(E): $(WOBJS)
+ $(LD) $(LDFLAGS) -o $@ $(WOBJS) $(WLIBSd)
+
+$(RPNG)$(O): $(RPNG).c readpng.h
+$(RPNG2)$(O): $(RPNG2).c readpng2.h
+$(WPNG)$(O): $(WPNG).c writepng.h
+
+readpng$(O): readpng.c readpng.h
+readpng2$(O): readpng2.c readpng2.h
+writepng$(O): writepng.c writepng.h
+
+
+# maintenance ---------------------------------------------------------------
+
+clean:
+ $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS)
diff --git a/contrib/gregbook/Makefile.w32 b/contrib/gregbook/Makefile.w32
new file mode 100644
index 0000000..3c08085
--- /dev/null
+++ b/contrib/gregbook/Makefile.w32
@@ -0,0 +1,113 @@
+# Sample makefile for rpng-win / rpng2-win / wpng using MSVC and NMAKE.
+# Greg Roelofs
+# Last modified: 2 June 2007
+#
+# The programs built by this makefile are described in the book,
+# "PNG: The Definitive Guide," by Greg Roelofs (O'Reilly and
+# Associates, 1999). Go buy a copy, eh? Well, OK, it's not
+# generally for sale anymore, but it's the thought that counts,
+# right? (Hint: http://www.libpng.org/pub/png/book/ )
+#
+# Invoke this makefile from a DOS prompt window via:
+#
+# %devstudio%\vc\bin\vcvars32.bat
+# nmake -nologo -f Makefile.w32
+#
+# where %devstudio% is the installation directory for MSVC / DevStudio. If
+# you get "environment out of space" errors, create a desktop shortcut with
+# "c:\windows\command.com /e:4096" as the program command line and set the
+# working directory to this directory. Then double-click to open the new
+# DOS-prompt window with a bigger environment and retry the commands above.
+#
+# This makefile assumes libpng and zlib have already been built or downloaded
+# and are in subdirectories at the same level as the current subdirectory
+# (as indicated by the PNGPATH and ZPATH macros below). Edit as appropriate.
+#
+# Note that the names of the dynamic and static libpng and zlib libraries
+# used below may change in later releases of the libraries. This makefile
+# builds statically linked executables, but that can be changed by uncom-
+# menting the appropriate PNGLIB and ZLIB lines.
+
+!include <ntwin32.mak>
+
+
+# macros --------------------------------------------------------------------
+
+PNGPATH = ../libpng
+PNGINC = -I$(PNGPATH)
+#PNGLIB = $(PNGPATH)/pngdll.lib
+PNGLIB = $(PNGPATH)/libpng.lib
+
+ZPATH = ../zlib
+ZINC = -I$(ZPATH)
+#ZLIB = $(ZPATH)/zlibdll.lib
+ZLIB = $(ZPATH)/zlibstat.lib
+
+WINLIBS = -defaultlib:user32.lib gdi32.lib
+# ["real" apps may also need comctl32.lib, comdlg32.lib, winmm.lib, etc.]
+
+INCS = $(PNGINC) $(ZINC)
+RLIBS = $(PNGLIB) $(ZLIB) $(WINLIBS)
+WLIBS = $(PNGLIB) $(ZLIB)
+
+CC = cl
+LD = link
+RM = del
+CFLAGS = -nologo -O -W3 $(INCS) $(cvars)
+# [note that -W3 is an MSVC-specific compilation flag ("all warnings on")]
+# [see %devstudio%\vc\include\win32.mak for cvars macro definition]
+O = .obj
+E = .exe
+
+RLDFLAGS = -nologo -subsystem:windows
+WLDFLAGS = -nologo
+
+RPNG = rpng-win
+RPNG2 = rpng2-win
+WPNG = wpng
+
+ROBJS = $(RPNG)$(O) readpng$(O)
+ROBJS2 = $(RPNG2)$(O) readpng2$(O)
+WOBJS = $(WPNG)$(O) writepng$(O)
+
+EXES = $(RPNG)$(E) $(RPNG2)$(E) $(WPNG)$(E)
+
+
+# implicit make rules -------------------------------------------------------
+
+.c$(O):
+ $(CC) -c $(CFLAGS) $<
+
+
+# dependencies --------------------------------------------------------------
+
+all: $(EXES)
+
+$(RPNG)$(E): $(ROBJS)
+ $(LD) $(RLDFLAGS) -out:$@ $(ROBJS) $(RLIBS)
+
+$(RPNG2)$(E): $(ROBJS2)
+ $(LD) $(RLDFLAGS) -out:$@ $(ROBJS2) $(RLIBS)
+
+$(WPNG)$(E): $(WOBJS)
+ $(LD) $(WLDFLAGS) -out:$@ $(WOBJS) $(WLIBS)
+
+$(RPNG)$(O): $(RPNG).c readpng.h
+$(RPNG2)$(O): $(RPNG2).c readpng2.h
+$(WPNG)$(O): $(WPNG).c writepng.h
+
+readpng$(O): readpng.c readpng.h
+readpng2$(O): readpng2.c readpng2.h
+writepng$(O): writepng.c writepng.h
+
+
+# maintenance ---------------------------------------------------------------
+
+clean:
+# ideally we could just do this:
+# $(RM) $(EXES) $(ROBJS) $(ROBJS2) $(WOBJS)
+# ...but the Windows "DEL" command is none too bright, so:
+ $(RM) r*$(E)
+ $(RM) w*$(E)
+ $(RM) r*$(O)
+ $(RM) w*$(O)
diff --git a/contrib/gregbook/README b/contrib/gregbook/README
new file mode 100644
index 0000000..cb6e525
--- /dev/null
+++ b/contrib/gregbook/README
@@ -0,0 +1,186 @@
+ ===========================
+ PNG: The Definitive Guide
+ ===========================
+
+ Source Code
+
+Chapters 13, 14 and 15 of "PNG: The Definitive Guide" discuss three free,
+cross-platform demo programs that show how to use the libpng reference
+library: rpng, rpng2 and wpng. rpng and rpng2 are viewers; the first is
+a very simple example that that shows how a standard file-viewer might use
+libpng, while the second is designed to process streaming data and shows
+how a web browser might be written. wpng is a simple command-line program
+that reads binary PGM and PPM files (the ``raw'' grayscale and RGB subsets
+of PBMPLUS/NetPBM) and converts them to PNG.
+
+The source code for all three demo programs currently compiles under
+Unix, OpenVMS, and 32-bit Windows. (Special thanks to Martin Zinser,
+zinser@decus.de, for making the necessary changes for OpenVMS and for
+providing an appropriate build script.) Build instructions can be found
+below.
+
+Files:
+
+ README this file
+ LICENSE terms of distribution and reuse (BSD-like or GNU GPL)
+ COPYING GNU General Public License (GPL)
+
+ Makefile.unx Unix makefile
+ Makefile.w32 Windows (MSVC) makefile
+ makevms.com OpenVMS build script
+
+ rpng-win.c Windows front end for the basic viewer
+ rpng-x.c X Window System (Unix, OpenVMS) front end
+ readpng.c generic back end for the basic viewer
+ readpng.h header file for the basic viewer
+
+ rpng2-win.c Windows front end for the progressive viewer
+ rpng2-x.c X front end for the progressive viewer
+ readpng2.c generic back end for the progressive viewer
+ readpng2.h header file for the progressive viewer
+
+ wpng.c generic (text) front end for the converter
+ writepng.c generic back end for the converter
+ writepng.h header file for the converter
+
+ toucan.png transparent PNG for testing (by Stefan Schneider)
+
+Note that, although the programs are designed to be functional, their
+primary purpose is to illustrate how to use libpng to add PNG support to
+other programs. As such, their user interfaces are crude and definitely
+are not intended for everyday use.
+
+Please see http://www.libpng.org/pub/png/pngbook.html for further infor-
+mation and links to the latest version of the source code, and Chapters
+13-15 of the book for detailed discussion of the three programs.
+
+Greg Roelofs
+http://pobox.com/~newt/greg_contact.html
+16 March 2008
+
+
+BUILD INSTRUCTIONS
+
+ - Prerequisites (in order of compilation):
+
+ - zlib http://zlib.net/
+ - libpng http://www.libpng.org/pub/png/libpng.html
+ - pngbook http://www.libpng.org/pub/png/book/sources.html
+
+ The pngbook demo programs are explicitly designed to demonstrate proper
+ coding techniques for using the libpng reference library. As a result,
+ you need to download and build both zlib (on which libpng depends) and
+ libpng. A common build setup is to place the zlib, libpng and pngbook
+ subdirectory trees ("folders") in the same parent directory. Then the
+ libpng build can refer to files in ../zlib (or ..\zlib or [-.zlib]),
+ and similarly for the pngbook build.
+
+ Note that all three packages are designed to be built from a command
+ line by default; those who wish to use a graphical or other integrated
+ development environments are on their own.
+
+
+ - Unix:
+
+ Unpack the latest pngbook sources (which should correspond to this
+ README file) into a directory and change into that directory.
+
+ Copy Makefile.unx to Makefile and edit the PNG* and Z* variables
+ appropriately (possibly also the X* variables if necessary).
+
+ make
+
+ There is no "install" target, so copy the three executables somewhere
+ in your path or run them from the current directory. All three will
+ print a basic usage screen when run without any command-line arguments;
+ see the book for more details.
+
+
+ - Windows:
+
+ Unpack the latest pngbook sources (which should correspond to this
+ README file) into a folder, open a "DOS shell" or "command prompt"
+ or equivalent command-line window, and cd into the folder where you
+ unpacked the source code.
+
+ For MSVC, set up the necessary environment variables by invoking
+
+ %devstudio%\vc\bin\vcvars32.bat
+
+ where where %devstudio% is the installation directory for MSVC /
+ DevStudio. If you get "environment out of space" errors under 95/98,
+ create a desktop shortcut with "c:\windows\command.com /e:4096" as
+ the program command line and set the working directory to the pngbook
+ directory. Then double-click to open the new DOS-prompt window with
+ a bigger environment and retry the commands above.
+
+ Copy Makefile.w32 to Makefile and edit the PNGPATH and ZPATH variables
+ appropriately (possibly also the "INC" and "LIB" variables if needed).
+ Note that the names of the dynamic and static libpng and zlib libraries
+ used in the makefile may change in later releases of the libraries.
+ Also note that, as of libpng version 1.0.5, MSVC DLL builds do not work.
+ This makefile therefore builds statically linked executables, but if
+ the DLL problems ever get fixed, uncommenting the appropriate PNGLIB
+ and ZLIB lines will build dynamically linked executables instead.
+
+ Do the build by typing
+
+ nmake
+
+ The result should be three executables: rpng-win.exe, rpng2-win.exe,
+ and wpng.exe. Copy them somewhere in your PATH or run them from the
+ current folder. Like the Unix versions, the two windowed programs
+ (rpng and rpng2) now display a usage screen in a console window when
+ invoked without command-line arguments; this is new behavior as of
+ the June 2001 release. Note that the programs use the Unix-style "-"
+ character to specify options, instead of the more common DOS/Windows
+ "/" character. (For example: "rpng2-win -bgpat 4 foo.png", not
+ "rpng2-win /bgpat 4 foo.png")
+
+
+ - OpenVMS:
+
+ Unpack the pngbook sources into a subdirectory and change into that
+ subdirectory.
+
+ Edit makevms.com appropriately, specifically the zpath and pngpath
+ variables.
+
+ @makevms
+
+ To run the programs, they probably first need to be set up as "foreign
+ symbols," with "disk" and "dir" set appropriately:
+
+ $ rpng == "$disk:[dir]rpng-x.exe"
+ $ rpng2 == "$disk:[dir]rpng2-x.exe"
+ $ wpng == "$disk:[dir]wpng.exe"
+
+ All three will print a basic usage screen when run without any command-
+ line arguments; see the book for more details. Note that the options
+ style is Unix-like, i.e., preceded by "-" rather than "/".
+
+
+RUNNING THE PROGRAMS: (VERY) BRIEF INTRO
+
+ rpng is a simple PNG viewer that can display transparent PNGs with a
+ specified background color; for example,
+
+ rpng -bgcolor #ff0000 toucan.png
+
+ would display the image with a red background. rpng2 is a progressive
+ viewer that simulates a web browser in some respects; it can display
+ images against either a background color or a dynamically generated
+ background image. For example:
+
+ rpng2 -bgpat 16 toucan.png
+
+ wpng is a purely command-line image converter from binary PBMPLUS/NetPBM
+ format (.pgm or .ppm) to PNG; for example,
+
+ wpng -time < toucan-notrans.ppm > toucan-notrans.png
+
+ would convert the specified PPM file (using redirection) to PNG, auto-
+ matically setting the PNG modification-time chunk.
+
+ All options can be abbreviated to the shortest unique value; for example,
+ "-bgc" for -bgcolor (versus "-bgp" for -bgpat), or "-g" for -gamma.
diff --git a/contrib/gregbook/makevms.com b/contrib/gregbook/makevms.com
new file mode 100644
index 0000000..bd37dc0
--- /dev/null
+++ b/contrib/gregbook/makevms.com
@@ -0,0 +1,132 @@
+$!------------------------------------------------------------------------------
+$! make "PNG: The Definitive Guide" demo programs (for X) under OpenVMS
+$!
+$! Script created by Martin Zinser for libpng; modified by Greg Roelofs
+$! for standalone pngbook source distribution.
+$!
+$!
+$! Set locations where zlib and libpng sources live.
+$!
+$ zpath = ""
+$ pngpath = ""
+$!
+$ if f$search("[---.zlib]zlib.h").nes."" then zpath = "[---.zlib]"
+$ if f$search("[--]png.h").nes."" then pngpath = "[--]"
+$!
+$ if f$search("[-.zlib]zlib.h").nes."" then zpath = "[-.zlib]"
+$ if f$search("[-.libpng]png.h").nes."" then pngpath = "[-.libpng]"
+$!
+$ if zpath .eqs. ""
+$ then
+$ write sys$output "zlib include not found. Exiting..."
+$ exit 2
+$ endif
+$!
+$ if pngpath .eqs. ""
+$ then
+$ write sys$output "libpng include not found. Exiting..."
+$ exit 2
+$ endif
+$!
+$! Look for the compiler used.
+$!
+$ ccopt="/include=(''zpath',''pngpath')"
+$ if f$getsyi("HW_MODEL").ge.1024
+$ then
+$ ccopt = "/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs.""
+$ then
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ if f$search("SYS$SYSTEM:VAXC.EXE").eqs.""
+$ then
+$ comp = "__gcc__=1"
+$ CC :== GCC
+$ else
+$ comp = "__vaxc__=1"
+$ endif
+$ else
+$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include:
+$ ccopt = "/decc/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ endif
+$ endif
+$ open/write lopt lib.opt
+$ write lopt "''pngpath'libpng.olb/lib"
+$ write lopt "''zpath'libz.olb/lib"
+$ close lopt
+$ open/write xopt x11.opt
+$ write xopt "sys$library:decw$xlibshr.exe/share"
+$ close xopt
+$!
+$! Build 'em.
+$!
+$ write sys$output "Compiling PNG book programs ..."
+$ CALL MAKE readpng.OBJ "cc ''CCOPT' readpng" -
+ readpng.c readpng.h
+$ CALL MAKE readpng2.OBJ "cc ''CCOPT' readpng2" -
+ readpng2.c readpng2.h
+$ CALL MAKE writepng.OBJ "cc ''CCOPT' writepng" -
+ writepng.c writepng.h
+$ write sys$output "Building rpng-x..."
+$ CALL MAKE rpng-x.OBJ "cc ''CCOPT' rpng-x" -
+ rpng-x.c readpng.h
+$ call make rpng-x.exe -
+ "LINK rpng-x,readpng,lib.opt/opt,x11.opt/opt" -
+ rpng-x.obj readpng.obj
+$ write sys$output "Building rpng2-x..."
+$ CALL MAKE rpng2-x.OBJ "cc ''CCOPT' rpng2-x" -
+ rpng2-x.c readpng2.h
+$ call make rpng2-x.exe -
+ "LINK rpng2-x,readpng2,lib.opt/opt,x11.opt/opt" -
+ rpng2-x.obj readpng2.obj
+$ write sys$output "Building wpng..."
+$ CALL MAKE wpng.OBJ "cc ''CCOPT' wpng" -
+ wpng.c writepng.h
+$ call make wpng.exe -
+ "LINK wpng,writepng,lib.opt/opt" -
+ wpng.obj writepng.obj
+$ exit
+$!
+$!
+$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8 What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$ Argument = P'arg
+$ If Argument .Eqs. "" Then Goto Exit
+$ El=0
+$Loop2:
+$ File = F$Element(El," ",Argument)
+$ If File .Eqs. " " Then Goto Endl
+$ AFile = ""
+$Loop3:
+$ OFile = AFile
+$ AFile = F$Search(File)
+$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$ Goto Loop3
+$NextEL:
+$ El = El + 1
+$ Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
diff --git a/contrib/gregbook/readpng.c b/contrib/gregbook/readpng.c
new file mode 100644
index 0000000..d87f6c7
--- /dev/null
+++ b/contrib/gregbook/readpng.c
@@ -0,0 +1,304 @@
+/*---------------------------------------------------------------------------
+
+ rpng - simple PNG display program readpng.c
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "png.h" /* libpng header; includes zlib.h */
+#include "readpng.h" /* typedefs, common macros, public prototypes */
+
+/* future versions of libpng will provide this macro: */
+#ifndef png_jmpbuf
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+
+static png_structp png_ptr = NULL;
+static png_infop info_ptr = NULL;
+
+png_uint_32 width, height;
+int bit_depth, color_type;
+uch *image_data = NULL;
+
+
+void readpng_version_info(void)
+{
+ fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n",
+ PNG_LIBPNG_VER_STRING, png_libpng_ver);
+ fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n",
+ ZLIB_VERSION, zlib_version);
+}
+
+
+/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */
+
+int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight)
+{
+ uch sig[8];
+
+
+ /* first do a quick check that the file really is a PNG image; could
+ * have used slightly more general png_sig_cmp() function instead */
+
+ fread(sig, 1, 8, infile);
+ if (!png_check_sig(sig, 8))
+ return 1; /* bad signature */
+
+
+ /* could pass pointers to user-defined error handlers instead of NULLs: */
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ return 4; /* out of memory */
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return 4; /* out of memory */
+ }
+
+
+ /* we could create a second info struct here (end_info), but it's only
+ * useful if we want to keep pre- and post-IDAT chunk info separated
+ * (mainly for PNG-aware image editors and converters) */
+
+
+ /* setjmp() must be called in every function that calls a PNG-reading
+ * libpng function */
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return 2;
+ }
+
+
+ png_init_io(png_ptr, infile);
+ png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */
+
+ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */
+
+
+ /* alternatively, could make separate calls to png_get_image_width(),
+ * etc., but want bit_depth and color_type for later [don't care about
+ * compression_type and filter_type => NULLs] */
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ NULL, NULL, NULL);
+ *pWidth = width;
+ *pHeight = height;
+
+
+ /* OK, that's all we need for now; return happy */
+
+ return 0;
+}
+
+
+
+
+/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error;
+ * scales values to 8-bit if necessary */
+
+int readpng_get_bgcolor(uch *red, uch *green, uch *blue)
+{
+ png_color_16p pBackground;
+
+
+ /* setjmp() must be called in every function that calls a PNG-reading
+ * libpng function */
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return 2;
+ }
+
+
+ if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
+ return 1;
+
+ /* it is not obvious from the libpng documentation, but this function
+ * takes a pointer to a pointer, and it always returns valid red, green
+ * and blue values, regardless of color_type: */
+
+ png_get_bKGD(png_ptr, info_ptr, &pBackground);
+
+
+ /* however, it always returns the raw bKGD data, regardless of any
+ * bit-depth transformations, so check depth and adjust if necessary */
+
+ if (bit_depth == 16) {
+ *red = pBackground->red >> 8;
+ *green = pBackground->green >> 8;
+ *blue = pBackground->blue >> 8;
+ } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
+ if (bit_depth == 1)
+ *red = *green = *blue = pBackground->gray? 255 : 0;
+ else if (bit_depth == 2)
+ *red = *green = *blue = (255/3) * pBackground->gray;
+ else /* bit_depth == 4 */
+ *red = *green = *blue = (255/15) * pBackground->gray;
+ } else {
+ *red = (uch)pBackground->red;
+ *green = (uch)pBackground->green;
+ *blue = (uch)pBackground->blue;
+ }
+
+ return 0;
+}
+
+
+
+
+/* display_exponent == LUT_exponent * CRT_exponent */
+
+uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes)
+{
+ double gamma;
+ png_uint_32 i, rowbytes;
+ png_bytepp row_pointers = NULL;
+
+
+ /* setjmp() must be called in every function that calls a PNG-reading
+ * libpng function */
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return NULL;
+ }
+
+
+ /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
+ * transparency chunks to full alpha channel; strip 16-bit-per-sample
+ * images to 8 bits per sample; and convert grayscale to RGB[A] */
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+
+ /* unlike the example in the libpng documentation, we have *no* idea where
+ * this file may have come from--so if it doesn't have a file gamma, don't
+ * do any correction ("do no harm") */
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, display_exponent, gamma);
+
+
+ /* all transformations have been registered; now update info_ptr data,
+ * get rowbytes and channels, and allocate image memory */
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ *pChannels = (int)png_get_channels(png_ptr, info_ptr);
+
+ if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return NULL;
+ }
+ if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ free(image_data);
+ image_data = NULL;
+ return NULL;
+ }
+
+ Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", *pChannels, rowbytes, height));
+
+
+ /* set the individual row_pointers to point at the correct offsets */
+
+ for (i = 0; i < height; ++i)
+ row_pointers[i] = image_data + i*rowbytes;
+
+
+ /* now we can go ahead and just read the whole image */
+
+ png_read_image(png_ptr, row_pointers);
+
+
+ /* and we're done! (png_read_end() can be omitted if no processing of
+ * post-IDAT text/time/etc. is desired) */
+
+ free(row_pointers);
+ row_pointers = NULL;
+
+ png_read_end(png_ptr, NULL);
+
+ return image_data;
+}
+
+
+void readpng_cleanup(int free_image_data)
+{
+ if (free_image_data && image_data) {
+ free(image_data);
+ image_data = NULL;
+ }
+
+ if (png_ptr && info_ptr) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_ptr = NULL;
+ info_ptr = NULL;
+ }
+}
diff --git a/contrib/gregbook/readpng.h b/contrib/gregbook/readpng.h
new file mode 100644
index 0000000..fad9fe3
--- /dev/null
+++ b/contrib/gregbook/readpng.h
@@ -0,0 +1,88 @@
+/*---------------------------------------------------------------------------
+
+ rpng - simple PNG display program readpng.h
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b)? (a) : (b))
+# define MIN(a,b) ((a) < (b)? (a) : (b))
+#endif
+
+#ifdef DEBUG
+# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);}
+#else
+# define Trace(x) ;
+#endif
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+
+/* prototypes for public functions in readpng.c */
+
+void readpng_version_info(void);
+
+int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight);
+
+int readpng_get_bgcolor(uch *bg_red, uch *bg_green, uch *bg_blue);
+
+uch *readpng_get_image(double display_exponent, int *pChannels,
+ ulg *pRowbytes);
+
+void readpng_cleanup(int free_image_data);
diff --git a/contrib/gregbook/readpng2.c b/contrib/gregbook/readpng2.c
new file mode 100644
index 0000000..9215042
--- /dev/null
+++ b/contrib/gregbook/readpng2.c
@@ -0,0 +1,645 @@
+/*---------------------------------------------------------------------------
+
+ rpng2 - progressive-model PNG display program readpng2.c
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+
+#include <stdlib.h> /* for exit() prototype */
+
+#include "png.h" /* libpng header; includes zlib.h and setjmp.h */
+#include "readpng2.h" /* typedefs, common macros, public prototypes */
+
+
+/* local prototypes */
+
+static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr);
+static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass);
+static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr);
+static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg);
+
+
+
+
+void readpng2_version_info(void)
+{
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
+ (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \
+ defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ /*
+ * WARNING: This preprocessor approach means that the following code
+ * cannot be used with a libpng DLL older than 1.2.0--the
+ * compiled-in symbols for the new functions will not exist.
+ * (Could use dlopen() and dlsym() on Unix and corresponding
+ * calls for Windows, but not portable...)
+ */
+ {
+ int mmxsupport = png_mmx_support();
+ if (mmxsupport < 0)
+ fprintf(stderr, " Compiled with libpng %s; using libpng %s "
+ "without MMX support.\n", PNG_LIBPNG_VER_STRING, png_libpng_ver);
+ else {
+ int compilerID;
+ png_uint_32 mmx_mask = png_get_mmx_flagmask(
+ PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID);
+
+ fprintf(stderr, " Compiled with libpng %s; using libpng %s "
+ "with MMX support\n (%s version).", PNG_LIBPNG_VER_STRING,
+ png_libpng_ver, compilerID == 1? "MSVC++" :
+ (compilerID == 2? "GNU C" : "unknown"));
+ fprintf(stderr, " Processor (x86%s) %s MMX instructions.\n",
+#if defined(__x86_64__)
+ "_64",
+#else
+ "",
+#endif
+ mmxsupport? "supports" : "does not support");
+ if (mmxsupport > 0) {
+ int num_optims = 0;
+
+ fprintf(stderr,
+ " Potential MMX optimizations supported by libpng:\n");
+ if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)
+ ++num_optims;
+ if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_UP)
+ ++num_optims;
+ if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)
+ ++num_optims;
+ if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)
+ ++num_optims;
+ if (num_optims)
+ fprintf(stderr,
+ " decoding %s row filters (reading)\n",
+ (num_optims == 4)? "all non-trivial" : "some");
+ if (mmx_mask & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) {
+ fprintf(stderr, " combining rows (reading)\n");
+ ++num_optims;
+ }
+ if (mmx_mask & PNG_ASM_FLAG_MMX_READ_INTERLACE) {
+ fprintf(stderr,
+ " expanding interlacing (reading)\n");
+ ++num_optims;
+ }
+ mmx_mask &= ~( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
+ if (mmx_mask) {
+ fprintf(stderr, " other (unknown)\n");
+ ++num_optims;
+ }
+ if (num_optims == 0)
+ fprintf(stderr, " (none)\n");
+ }
+ }
+ }
+#else
+ fprintf(stderr, " Compiled with libpng %s; using libpng %s "
+ "without MMX support.\n", PNG_LIBPNG_VER_STRING, png_libpng_ver);
+#endif
+
+ fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n",
+ ZLIB_VERSION, zlib_version);
+}
+
+
+
+
+int readpng2_check_sig(uch *sig, int num)
+{
+ return png_check_sig(sig, num);
+}
+
+
+
+
+/* returns 0 for success, 2 for libpng problem, 4 for out of memory */
+
+int readpng2_init(mainprog_info *mainprog_ptr)
+{
+ png_structp png_ptr; /* note: temporary variables! */
+ png_infop info_ptr;
+
+
+ /* could also replace libpng warning-handler (final NULL), but no need: */
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
+ readpng2_error_handler, NULL);
+ if (!png_ptr)
+ return 4; /* out of memory */
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return 4; /* out of memory */
+ }
+
+
+ /* we could create a second info struct here (end_info), but it's only
+ * useful if we want to keep pre- and post-IDAT chunk info separated
+ * (mainly for PNG-aware image editors and converters) */
+
+
+ /* setjmp() must be called in every function that calls a PNG-reading
+ * libpng function, unless an alternate error handler was installed--
+ * but compatible error handlers must either use longjmp() themselves
+ * (as in this program) or exit immediately, so here we are: */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return 2;
+ }
+
+
+#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
+ /* prepare the reader to ignore all recognized chunks whose data won't be
+ * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT,
+ * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */
+ {
+ /* These byte strings were copied from png.h. If a future libpng
+ * version recognizes more chunks, add them to this list. If a
+ * future version of readpng2.c recognizes more chunks, delete them
+ * from this list. */
+ static const png_byte chunks_to_ignore[] = {
+ 99, 72, 82, 77, '\0', /* cHRM */
+ 104, 73, 83, 84, '\0', /* hIST */
+ 105, 67, 67, 80, '\0', /* iCCP */
+ 105, 84, 88, 116, '\0', /* iTXt */
+ 111, 70, 70, 115, '\0', /* oFFs */
+ 112, 67, 65, 76, '\0', /* pCAL */
+ 112, 72, 89, 115, '\0', /* pHYs */
+ 115, 66, 73, 84, '\0', /* sBIT */
+ 115, 67, 65, 76, '\0', /* sCAL */
+ 115, 80, 76, 84, '\0', /* sPLT */
+ 115, 84, 69, 82, '\0', /* sTER */
+ 116, 69, 88, 116, '\0', /* tEXt */
+ 116, 73, 77, 69, '\0', /* tIME */
+ 122, 84, 88, 116, '\0' /* zTXt */
+ };
+
+ png_set_keep_unknown_chunks(png_ptr, 1 /* PNG_HANDLE_CHUNK_NEVER */,
+ chunks_to_ignore, sizeof(chunks_to_ignore)/5);
+ }
+#endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */
+
+
+ /* instead of doing png_init_io() here, now we set up our callback
+ * functions for progressive decoding */
+
+ png_set_progressive_read_fn(png_ptr, mainprog_ptr,
+ readpng2_info_callback, readpng2_row_callback, readpng2_end_callback);
+
+
+ /*
+ * may as well enable or disable MMX routines here, if supported;
+ *
+ * to enable all: mask = png_get_mmx_flagmask (
+ * PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID);
+ * flags = png_get_asm_flags (png_ptr);
+ * flags |= mask;
+ * png_set_asm_flags (png_ptr, flags);
+ *
+ * to disable all: mask = png_get_mmx_flagmask (
+ * PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID);
+ * flags = png_get_asm_flags (png_ptr);
+ * flags &= ~mask;
+ * png_set_asm_flags (png_ptr, flags);
+ */
+
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \
+ defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ /*
+ * WARNING: This preprocessor approach means that the following code
+ * cannot be used with a libpng DLL older than 1.2.0--the
+ * compiled-in symbols for the new functions will not exist.
+ * (Could use dlopen() and dlsym() on Unix and corresponding
+ * calls for Windows, but not portable...)
+ */
+ {
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+ png_uint_32 mmx_disable_mask = 0;
+ png_uint_32 asm_flags, mmx_mask;
+ int compilerID;
+
+ if (mainprog_ptr->nommxfilters)
+ mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
+ if (mainprog_ptr->nommxcombine)
+ mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_COMBINE_ROW;
+ if (mainprog_ptr->nommxinterlace)
+ mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_INTERLACE;
+ asm_flags = png_get_asm_flags(png_ptr);
+ png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask);
+
+
+ /* Now query libpng's asm settings, just for yuks. Note that this
+ * differs from the querying of its *potential* MMX capabilities
+ * in readpng2_version_info(); this is true runtime verification. */
+
+ asm_flags = png_get_asm_flags(png_ptr);
+ mmx_mask = png_get_mmx_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE,
+ &compilerID);
+ if (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_COMPILED)
+ fprintf(stderr,
+ " MMX support (%s version) is compiled into libpng\n",
+ compilerID == 1? "MSVC++" :
+ (compilerID == 2? "GNU C" : "unknown"));
+ else
+ fprintf(stderr, " MMX support is not compiled into libpng\n");
+ fprintf(stderr, " MMX instructions are %ssupported by CPU\n",
+ (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU)? "" : "not ");
+ fprintf(stderr, " MMX read support for combining rows is %sabled\n",
+ (asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)? "en" : "dis");
+ fprintf(stderr,
+ " MMX read support for expanding interlacing is %sabled\n",
+ (asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)? "en" : "dis");
+ fprintf(stderr, " MMX read support for \"sub\" filter is %sabled\n",
+ (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "en" : "dis");
+ fprintf(stderr, " MMX read support for \"up\" filter is %sabled\n",
+ (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "en" : "dis");
+ fprintf(stderr, " MMX read support for \"avg\" filter is %sabled\n",
+ (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "en" : "dis");
+ fprintf(stderr, " MMX read support for \"Paeth\" filter is %sabled\n",
+ (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "en" : "dis");
+ asm_flags &= (mmx_mask & ~( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ));
+ if (asm_flags)
+ fprintf(stderr,
+ " additional MMX support is also enabled (0x%02lx)\n",
+ asm_flags);
+#else /* !PNG_ASSEMBLER_CODE_SUPPORTED */
+ fprintf(stderr, " MMX querying is disabled in libpng.\n");
+#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
+ }
+#endif
+
+
+ /* make sure we save our pointers for use in readpng2_decode_data() */
+
+ mainprog_ptr->png_ptr = png_ptr;
+ mainprog_ptr->info_ptr = info_ptr;
+
+
+ /* and that's all there is to initialization */
+
+ return 0;
+}
+
+
+
+
+/* returns 0 for success, 2 for libpng (longjmp) problem */
+
+int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length)
+{
+ png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
+ png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
+
+
+ /* setjmp() must be called in every function that calls a PNG-reading
+ * libpng function */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ mainprog_ptr->png_ptr = NULL;
+ mainprog_ptr->info_ptr = NULL;
+ return 2;
+ }
+
+
+ /* hand off the next chunk of input data to libpng for decoding */
+
+ png_process_data(png_ptr, info_ptr, rawbuf, length);
+
+ return 0;
+}
+
+
+
+
+static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr)
+{
+ mainprog_info *mainprog_ptr;
+ int color_type, bit_depth;
+ double gamma;
+
+
+ /* setjmp() doesn't make sense here, because we'd either have to exit(),
+ * longjmp() ourselves, or return control to libpng, which doesn't want
+ * to see us again. By not doing anything here, libpng will instead jump
+ * to readpng2_decode_data(), which can return an error value to the main
+ * program. */
+
+
+ /* retrieve the pointer to our special-purpose struct, using the png_ptr
+ * that libpng passed back to us (i.e., not a global this time--there's
+ * no real difference for a single image, but for a multithreaded browser
+ * decoding several PNG images at the same time, one needs to avoid mixing
+ * up different images' structs) */
+
+ mainprog_ptr = png_get_progressive_ptr(png_ptr);
+
+ if (mainprog_ptr == NULL) { /* we be hosed */
+ fprintf(stderr,
+ "readpng2 error: main struct not recoverable in info_callback.\n");
+ fflush(stderr);
+ return;
+ /*
+ * Alternatively, we could call our error-handler just like libpng
+ * does, which would effectively terminate the program. Since this
+ * can only happen if png_ptr gets redirected somewhere odd or the
+ * main PNG struct gets wiped, we're probably toast anyway. (If
+ * png_ptr itself is NULL, we would not have been called.)
+ */
+ }
+
+
+ /* this is just like in the non-progressive case */
+
+ png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width,
+ &mainprog_ptr->height, &bit_depth, &color_type, NULL, NULL, NULL);
+
+
+ /* since we know we've read all of the PNG file's "header" (i.e., up
+ * to IDAT), we can check for a background color here */
+
+ if (mainprog_ptr->need_bgcolor &&
+ png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
+ {
+ png_color_16p pBackground;
+
+ /* it is not obvious from the libpng documentation, but this function
+ * takes a pointer to a pointer, and it always returns valid red,
+ * green and blue values, regardless of color_type: */
+ png_get_bKGD(png_ptr, info_ptr, &pBackground);
+
+ /* however, it always returns the raw bKGD data, regardless of any
+ * bit-depth transformations, so check depth and adjust if necessary */
+ if (bit_depth == 16) {
+ mainprog_ptr->bg_red = pBackground->red >> 8;
+ mainprog_ptr->bg_green = pBackground->green >> 8;
+ mainprog_ptr->bg_blue = pBackground->blue >> 8;
+ } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
+ if (bit_depth == 1)
+ mainprog_ptr->bg_red = mainprog_ptr->bg_green =
+ mainprog_ptr->bg_blue = pBackground->gray? 255 : 0;
+ else if (bit_depth == 2)
+ mainprog_ptr->bg_red = mainprog_ptr->bg_green =
+ mainprog_ptr->bg_blue = (255/3) * pBackground->gray;
+ else /* bit_depth == 4 */
+ mainprog_ptr->bg_red = mainprog_ptr->bg_green =
+ mainprog_ptr->bg_blue = (255/15) * pBackground->gray;
+ } else {
+ mainprog_ptr->bg_red = (uch)pBackground->red;
+ mainprog_ptr->bg_green = (uch)pBackground->green;
+ mainprog_ptr->bg_blue = (uch)pBackground->blue;
+ }
+ }
+
+
+ /* as before, let libpng expand palette images to RGB, low-bit-depth
+ * grayscale images to 8 bits, transparency chunks to full alpha channel;
+ * strip 16-bit-per-sample images to 8 bits per sample; and convert
+ * grayscale to RGB[A] */
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+
+ /* Unlike the basic viewer, which was designed to operate on local files,
+ * this program is intended to simulate a web browser--even though we
+ * actually read from a local file, too. But because we are pretending
+ * that most of the images originate on the Internet, we follow the recom-
+ * mendation of the sRGB proposal and treat unlabelled images (no gAMA
+ * chunk) as existing in the sRGB color space. That is, we assume that
+ * such images have a file gamma of 0.45455, which corresponds to a PC-like
+ * display system. This change in assumptions will have no effect on a
+ * PC-like system, but on a Mac, SGI, NeXT or other system with a non-
+ * identity lookup table, it will darken unlabelled images, which effec-
+ * tively favors images from PC-like systems over those originating on
+ * the local platform. Note that mainprog_ptr->display_exponent is the
+ * "gamma" value for the entire display system, i.e., the product of
+ * LUT_exponent and CRT_exponent. */
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, mainprog_ptr->display_exponent, gamma);
+ else
+ png_set_gamma(png_ptr, mainprog_ptr->display_exponent, 0.45455);
+
+
+ /* we'll let libpng expand interlaced images, too */
+
+ mainprog_ptr->passes = png_set_interlace_handling(png_ptr);
+
+
+ /* all transformations have been registered; now update info_ptr data and
+ * then get rowbytes and channels */
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ mainprog_ptr->rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr);
+ mainprog_ptr->channels = png_get_channels(png_ptr, info_ptr);
+
+
+ /* Call the main program to allocate memory for the image buffer and
+ * initialize windows and whatnot. (The old-style function-pointer
+ * invocation is used for compatibility with a few supposedly ANSI
+ * compilers that nevertheless barf on "fn_ptr()"-style syntax.) */
+
+ (*mainprog_ptr->mainprog_init)();
+
+
+ /* and that takes care of initialization */
+
+ return;
+}
+
+
+
+
+
+static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+{
+ mainprog_info *mainprog_ptr;
+
+
+ /* first check whether the row differs from the previous pass; if not,
+ * nothing to combine or display */
+
+ if (!new_row)
+ return;
+
+
+ /* retrieve the pointer to our special-purpose struct so we can access
+ * the old rows and image-display callback function */
+
+ mainprog_ptr = png_get_progressive_ptr(png_ptr);
+
+
+ /* save the pass number for optional use by the front end */
+
+ mainprog_ptr->pass = pass;
+
+
+ /* have libpng either combine the new row data with the existing row data
+ * from previous passes (if interlaced) or else just copy the new row
+ * into the main program's image buffer */
+
+ png_progressive_combine_row(png_ptr, mainprog_ptr->row_pointers[row_num],
+ new_row);
+
+
+ /* finally, call the display routine in the main program with the number
+ * of the row we just updated */
+
+ (*mainprog_ptr->mainprog_display_row)(row_num);
+
+
+ /* and we're ready for more */
+
+ return;
+}
+
+
+
+
+
+static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr)
+{
+ mainprog_info *mainprog_ptr;
+
+
+ /* retrieve the pointer to our special-purpose struct */
+
+ mainprog_ptr = png_get_progressive_ptr(png_ptr);
+
+
+ /* let the main program know that it should flush any buffered image
+ * data to the display now and set a "done" flag or whatever, but note
+ * that it SHOULD NOT DESTROY THE PNG STRUCTS YET--in other words, do
+ * NOT call readpng2_cleanup() either here or in the finish_display()
+ * routine; wait until control returns to the main program via
+ * readpng2_decode_data() */
+
+ (*mainprog_ptr->mainprog_finish_display)();
+
+
+ /* all done */
+
+ return;
+}
+
+
+
+
+
+void readpng2_cleanup(mainprog_info *mainprog_ptr)
+{
+ png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
+ png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
+
+ if (png_ptr && info_ptr)
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+ mainprog_ptr->png_ptr = NULL;
+ mainprog_ptr->info_ptr = NULL;
+}
+
+
+
+
+
+static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg)
+{
+ mainprog_info *mainprog_ptr;
+
+ /* This function, aside from the extra step of retrieving the "error
+ * pointer" (below) and the fact that it exists within the application
+ * rather than within libpng, is essentially identical to libpng's
+ * default error handler. The second point is critical: since both
+ * setjmp() and longjmp() are called from the same code, they are
+ * guaranteed to have compatible notions of how big a jmp_buf is,
+ * regardless of whether _BSD_SOURCE or anything else has (or has not)
+ * been defined. */
+
+ fprintf(stderr, "readpng2 libpng error: %s\n", msg);
+ fflush(stderr);
+
+ mainprog_ptr = png_get_error_ptr(png_ptr);
+ if (mainprog_ptr == NULL) { /* we are completely hosed now */
+ fprintf(stderr,
+ "readpng2 severe error: jmpbuf not recoverable; terminating.\n");
+ fflush(stderr);
+ exit(99);
+ }
+
+ longjmp(mainprog_ptr->jmpbuf, 1);
+}
diff --git a/contrib/gregbook/readpng2.h b/contrib/gregbook/readpng2.h
new file mode 100644
index 0000000..fbfffb4
--- /dev/null
+++ b/contrib/gregbook/readpng2.h
@@ -0,0 +1,121 @@
+/*---------------------------------------------------------------------------
+
+ rpng2 - progressive-model PNG display program readpng2.h
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b)? (a) : (b))
+# define MIN(a,b) ((a) < (b)? (a) : (b))
+#endif
+
+#ifdef DEBUG
+# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);}
+#else
+# define Trace(x) ;
+#endif
+
+enum rpng2_states {
+ kPreInit = 0,
+ kWindowInit,
+ kDone
+};
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+typedef struct _mainprog_info {
+ double display_exponent;
+ ulg width;
+ ulg height;
+ void *png_ptr;
+ void *info_ptr;
+ void (*mainprog_init)(void);
+ void (*mainprog_display_row)(ulg row_num);
+ void (*mainprog_finish_display)(void);
+ uch *image_data;
+ uch **row_pointers;
+ jmp_buf jmpbuf;
+ int passes; /* not used */
+ int pass;
+ int rowbytes;
+ int channels;
+ int need_bgcolor;
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ int nommxfilters;
+ int nommxcombine;
+ int nommxinterlace;
+#endif
+ int state;
+ uch bg_red;
+ uch bg_green;
+ uch bg_blue;
+} mainprog_info;
+
+
+/* prototypes for public functions in readpng2.c */
+
+void readpng2_version_info(void);
+
+int readpng2_check_sig(uch *sig, int num);
+
+int readpng2_init(mainprog_info *mainprog_ptr);
+
+int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length);
+
+void readpng2_cleanup(mainprog_info *mainprog_ptr);
diff --git a/contrib/gregbook/readppm.c b/contrib/gregbook/readppm.c
new file mode 100644
index 0000000..be9a56d
--- /dev/null
+++ b/contrib/gregbook/readppm.c
@@ -0,0 +1,179 @@
+/*---------------------------------------------------------------------------
+
+ rpng - simple PNG display program readppm.c
+
+ ---------------------------------------------------------------------------
+
+ This is a special-purpose replacement for readpng.c that allows binary
+ PPM files to be used in place of PNG images.
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "readpng.h" /* typedefs, common macros, public prototypes */
+
+
+ulg width, height;
+int bit_depth, color_type, channels;
+uch *image_data = NULL;
+FILE *saved_infile;
+
+
+void readpng_version_info()
+{
+ fprintf(stderr, " Compiled without libpng, zlib or PBMPLUS/NetPBM.\n");
+}
+
+
+/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */
+
+int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight)
+{
+ static uch ppmline[256];
+ int maxval;
+
+
+ saved_infile = infile;
+
+ fgets(ppmline, 256, infile);
+ if (ppmline[0] != 'P' || ppmline[1] != '6') {
+ fprintf(stderr, "ERROR: not a PPM file\n");
+ return 1;
+ }
+ /* possible color types: P5 = grayscale (0), P6 = RGB (2), P8 = RGBA (6) */
+ if (ppmline[1] == '6') {
+ color_type = 2;
+ channels = 3;
+ } else if (ppmline[1] == '8') {
+ color_type = 6;
+ channels = 4;
+ } else /* if (ppmline[1] == '5') */ {
+ color_type = 0;
+ channels = 1;
+ }
+
+ do {
+ fgets(ppmline, 256, infile);
+ } while (ppmline[0] == '#');
+ sscanf(ppmline, "%lu %lu", &width, &height);
+
+ do {
+ fgets(ppmline, 256, infile);
+ } while (ppmline[0] == '#');
+ sscanf(ppmline, "%d", &maxval);
+ if (maxval != 255) {
+ fprintf(stderr, "ERROR: maxval = %d\n", maxval);
+ return 2;
+ }
+ bit_depth = 8;
+
+ *pWidth = width;
+ *pHeight = height;
+
+ return 0;
+}
+
+
+
+
+/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error;
+ * scales values to 8-bit if necessary */
+
+int readpng_get_bgcolor(uch *red, uch *green, uch *blue)
+{
+ return 1;
+}
+
+
+
+
+/* display_exponent == LUT_exponent * CRT_exponent */
+
+uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes)
+{
+ ulg rowbytes;
+
+
+ /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
+ * transparency chunks to full alpha channel; strip 16-bit-per-sample
+ * images to 8 bits per sample; and convert grayscale to RGB[A] */
+
+ /* GRR WARNING: grayscale needs to be expanded and channels reset! */
+
+ *pRowbytes = rowbytes = channels*width;
+ *pChannels = channels;
+
+ if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) {
+ return NULL;
+ }
+
+ Trace((stderr, "readpng_get_image: rowbytes = %ld, height = %ld\n", rowbytes, height));
+
+
+ /* now we can go ahead and just read the whole image */
+
+ fread(image_data, 1L, rowbytes*height, saved_infile);
+
+
+ return image_data;
+}
+
+
+void readpng_cleanup(int free_image_data)
+{
+ if (free_image_data && image_data) {
+ free(image_data);
+ image_data = NULL;
+ }
+}
diff --git a/contrib/gregbook/rpng-win.c b/contrib/gregbook/rpng-win.c
new file mode 100644
index 0000000..2020961
--- /dev/null
+++ b/contrib/gregbook/rpng-win.c
@@ -0,0 +1,684 @@
+/*---------------------------------------------------------------------------
+
+ rpng - simple PNG display program rpng-win.c
+
+ This program decodes and displays PNG images, with gamma correction and
+ optionally with a user-specified background color (in case the image has
+ transparency). It is very nearly the most basic PNG viewer possible.
+ This version is for 32-bit Windows; it may compile under 16-bit Windows
+ with a little tweaking (or maybe not).
+
+ to do:
+ - handle quoted command-line args (especially filenames with spaces)
+ - have minimum window width: oh well
+ - use %.1023s to simplify truncation of title-bar string?
+
+ ---------------------------------------------------------------------------
+
+ Changelog:
+ - 1.00: initial public release
+ - 1.01: modified to allow abbreviated options; fixed long/ulong mis-
+ match; switched to png_jmpbuf() macro
+ - 1.02: added extra set of parentheses to png_jmpbuf() macro; fixed
+ command-line parsing bug
+ - 1.10: enabled "message window"/console (thanks to David Geldreich)
+ - 2.00: dual-licensed (added GNU GPL)
+ - 2.01: fixed improper display of usage screen on PNG error(s)
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#define PROGNAME "rpng-win"
+#define LONGNAME "Simple PNG Viewer for Windows"
+#define VERSION "2.01 of 16 March 2008"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <windows.h>
+#include <conio.h> /* only for _getch() */
+
+/* #define DEBUG : this enables the Trace() macros */
+
+#include "readpng.h" /* typedefs, common macros, readpng prototypes */
+
+
+/* could just include png.h, but this macro is the only thing we need
+ * (name and typedefs changed to local versions); note that side effects
+ * only happen with alpha (which could easily be avoided with
+ * "ush acopy = (alpha);") */
+
+#define alpha_composite(composite, fg, alpha, bg) { \
+ ush temp = ((ush)(fg)*(ush)(alpha) + \
+ (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
+ (composite) = (uch)((temp + (temp >> 8)) >> 8); \
+}
+
+
+/* local prototypes */
+static int rpng_win_create_window(HINSTANCE hInst, int showmode);
+static int rpng_win_display_image(void);
+static void rpng_win_cleanup(void);
+LRESULT CALLBACK rpng_win_wndproc(HWND, UINT, WPARAM, LPARAM);
+
+
+static char titlebar[1024];
+static char *progname = PROGNAME;
+static char *appname = LONGNAME;
+static char *filename;
+static FILE *infile;
+
+static char *bgstr;
+static uch bg_red=0, bg_green=0, bg_blue=0;
+
+static double display_exponent;
+
+static ulg image_width, image_height, image_rowbytes;
+static int image_channels;
+static uch *image_data;
+
+/* Windows-specific variables */
+static ulg wimage_rowbytes;
+static uch *dib;
+static uch *wimage_data;
+static BITMAPINFOHEADER *bmih;
+
+static HWND global_hwnd;
+
+
+
+
+int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode)
+{
+ char *args[1024]; /* arbitrary limit, but should suffice */
+ char *p, *q, **argv = args;
+ int argc = 0;
+ int rc, alen, flen;
+ int error = 0;
+ int have_bg = FALSE;
+ double LUT_exponent; /* just the lookup table */
+ double CRT_exponent = 2.2; /* just the monitor */
+ double default_display_exponent; /* whole display system */
+ MSG msg;
+
+
+ filename = (char *)NULL;
+
+
+ /* First reenable console output, which normally goes to the bit bucket
+ * for windowed apps. Closing the console window will terminate the
+ * app. Thanks to David.Geldreich@realviz.com for supplying the magical
+ * incantation. */
+
+ AllocConsole();
+ freopen("CONOUT$", "a", stderr);
+ freopen("CONOUT$", "a", stdout);
+
+
+ /* Next set the default value for our display-system exponent, i.e.,
+ * the product of the CRT exponent and the exponent corresponding to
+ * the frame-buffer's lookup table (LUT), if any. This is not an
+ * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
+ * ones), but it should cover 99% of the current possibilities. And
+ * yes, these ifdefs are completely wasted in a Windows program... */
+
+#if defined(NeXT)
+ LUT_exponent = 1.0 / 2.2;
+ /*
+ if (some_next_function_that_returns_gamma(&next_gamma))
+ LUT_exponent = 1.0 / next_gamma;
+ */
+#elif defined(sgi)
+ LUT_exponent = 1.0 / 1.7;
+ /* there doesn't seem to be any documented function to get the
+ * "gamma" value, so we do it the hard way */
+ infile = fopen("/etc/config/system.glGammaVal", "r");
+ if (infile) {
+ double sgi_gamma;
+
+ fgets(tmpline, 80, infile);
+ fclose(infile);
+ sgi_gamma = atof(tmpline);
+ if (sgi_gamma > 0.0)
+ LUT_exponent = 1.0 / sgi_gamma;
+ }
+#elif defined(Macintosh)
+ LUT_exponent = 1.8 / 2.61;
+ /*
+ if (some_mac_function_that_returns_gamma(&mac_gamma))
+ LUT_exponent = mac_gamma / 2.61;
+ */
+#else
+ LUT_exponent = 1.0; /* assume no LUT: most PCs */
+#endif
+
+ /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
+ default_display_exponent = LUT_exponent * CRT_exponent;
+
+
+ /* If the user has set the SCREEN_GAMMA environment variable as suggested
+ * (somewhat imprecisely) in the libpng documentation, use that; otherwise
+ * use the default value we just calculated. Either way, the user may
+ * override this via a command-line option. */
+
+ if ((p = getenv("SCREEN_GAMMA")) != NULL)
+ display_exponent = atof(p);
+ else
+ display_exponent = default_display_exponent;
+
+
+ /* Windows really hates command lines, so we have to set up our own argv.
+ * Note that we do NOT bother with quoted arguments here, so don't use
+ * filenames with spaces in 'em! */
+
+ argv[argc++] = PROGNAME;
+ p = cmd;
+ for (;;) {
+ if (*p == ' ')
+ while (*++p == ' ')
+ ;
+ /* now p points at the first non-space after some spaces */
+ if (*p == '\0')
+ break; /* nothing after the spaces: done */
+ argv[argc++] = q = p;
+ while (*q && *q != ' ')
+ ++q;
+ /* now q points at a space or the end of the string */
+ if (*q == '\0')
+ break; /* last argv already terminated; quit */
+ *q = '\0'; /* change space to terminator */
+ p = q + 1;
+ }
+ argv[argc] = NULL; /* terminate the argv array itself */
+
+
+ /* Now parse the command line for options and the PNG filename. */
+
+ while (*++argv && !error) {
+ if (!strncmp(*argv, "-gamma", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ display_exponent = atof(*argv);
+ if (display_exponent <= 0.0)
+ ++error;
+ }
+ } else if (!strncmp(*argv, "-bgcolor", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ bgstr = *argv;
+ if (strlen(bgstr) != 7 || bgstr[0] != '#')
+ ++error;
+ else
+ have_bg = TRUE;
+ }
+ } else {
+ if (**argv != '-') {
+ filename = *argv;
+ if (argv[1]) /* shouldn't be any more args after filename */
+ ++error;
+ } else
+ ++error; /* not expecting any other options */
+ }
+ }
+
+ if (!filename)
+ ++error;
+
+
+ /* print usage screen if any errors up to this point */
+
+ if (error) {
+ int ch;
+
+ fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname);
+ readpng_version_info();
+ fprintf(stderr, "\n"
+ "Usage: %s [-gamma exp] [-bgcolor bg] file.png\n"
+ " exp \ttransfer-function exponent (``gamma'') of the display\n"
+ "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
+ "\t\t to the product of the lookup-table exponent (varies)\n"
+ "\t\t and the CRT exponent (usually 2.2); must be positive\n"
+ " bg \tdesired background color in 7-character hex RGB format\n"
+ "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
+ "\t\t used with transparent images\n"
+ "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n"
+ "Press Q or Esc to quit this usage screen.\n"
+ "\n", PROGNAME, default_display_exponent);
+ do
+ ch = _getch();
+ while (ch != 'q' && ch != 'Q' && ch != 0x1B);
+ exit(1);
+ }
+
+
+ if (!(infile = fopen(filename, "rb"))) {
+ fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
+ ++error;
+ } else {
+ if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
+ switch (rc) {
+ case 1:
+ fprintf(stderr, PROGNAME
+ ": [%s] is not a PNG file: incorrect signature\n",
+ filename);
+ break;
+ case 2:
+ fprintf(stderr, PROGNAME
+ ": [%s] has bad IHDR (libpng longjmp)\n", filename);
+ break;
+ case 4:
+ fprintf(stderr, PROGNAME ": insufficient memory\n");
+ break;
+ default:
+ fprintf(stderr, PROGNAME
+ ": unknown readpng_init() error\n");
+ break;
+ }
+ ++error;
+ }
+ if (error)
+ fclose(infile);
+ }
+
+
+ if (error) {
+ int ch;
+
+ fprintf(stderr, PROGNAME ": aborting.\n");
+ do
+ ch = _getch();
+ while (ch != 'q' && ch != 'Q' && ch != 0x1B);
+ exit(2);
+ } else {
+ fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname);
+ fprintf(stderr,
+ "\n [console window: closing this window will terminate %s]\n\n",
+ PROGNAME);
+ }
+
+
+ /* set the title-bar string, but make sure buffer doesn't overflow */
+
+ alen = strlen(appname);
+ flen = strlen(filename);
+ if (alen + flen + 3 > 1023)
+ sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
+ else
+ sprintf(titlebar, "%s: %s", appname, filename);
+
+
+ /* if the user didn't specify a background color on the command line,
+ * check for one in the PNG file--if not, the initialized values of 0
+ * (black) will be used */
+
+ if (have_bg) {
+ unsigned r, g, b; /* this approach quiets compiler warnings */
+
+ sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
+ bg_red = (uch)r;
+ bg_green = (uch)g;
+ bg_blue = (uch)b;
+ } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) {
+ readpng_cleanup(TRUE);
+ fprintf(stderr, PROGNAME
+ ": libpng error while checking for background color\n");
+ exit(2);
+ }
+
+
+ /* do the basic Windows initialization stuff, make the window and fill it
+ * with the background color */
+
+ if (rpng_win_create_window(hInst, showmode))
+ exit(2);
+
+
+ /* decode the image, all at once */
+
+ Trace((stderr, "calling readpng_get_image()\n"))
+ image_data = readpng_get_image(display_exponent, &image_channels,
+ &image_rowbytes);
+ Trace((stderr, "done with readpng_get_image()\n"))
+
+
+ /* done with PNG file, so clean up to minimize memory usage (but do NOT
+ * nuke image_data!) */
+
+ readpng_cleanup(FALSE);
+ fclose(infile);
+
+ if (!image_data) {
+ fprintf(stderr, PROGNAME ": unable to decode PNG image\n");
+ exit(3);
+ }
+
+
+ /* display image (composite with background if requested) */
+
+ Trace((stderr, "calling rpng_win_display_image()\n"))
+ if (rpng_win_display_image()) {
+ free(image_data);
+ exit(4);
+ }
+ Trace((stderr, "done with rpng_win_display_image()\n"))
+
+
+ /* wait for the user to tell us when to quit */
+
+ printf(
+ "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
+ fflush(stdout);
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+
+ /* OK, we're done: clean up all image and Windows resources and go away */
+
+ rpng_win_cleanup();
+
+ return msg.wParam;
+}
+
+
+
+
+
+static int rpng_win_create_window(HINSTANCE hInst, int showmode)
+{
+ uch *dest;
+ int extra_width, extra_height;
+ ulg i, j;
+ WNDCLASSEX wndclass;
+
+
+/*---------------------------------------------------------------------------
+ Allocate memory for the display-specific version of the image (round up
+ to multiple of 4 for Windows DIB).
+ ---------------------------------------------------------------------------*/
+
+ wimage_rowbytes = ((3*image_width + 3L) >> 2) << 2;
+
+ if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) +
+ wimage_rowbytes*image_height)))
+ {
+ return 4; /* fail */
+ }
+
+/*---------------------------------------------------------------------------
+ Initialize the DIB. Negative height means to use top-down BMP ordering
+ (must be uncompressed, but that's what we want). Bit count of 1, 4 or 8
+ implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values
+ directly => wimage_data begins immediately after BMP header.
+ ---------------------------------------------------------------------------*/
+
+ memset(dib, 0, sizeof(BITMAPINFOHEADER));
+ bmih = (BITMAPINFOHEADER *)dib;
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = image_width;
+ bmih->biHeight = -((long)image_height);
+ bmih->biPlanes = 1;
+ bmih->biBitCount = 24;
+ bmih->biCompression = 0;
+ wimage_data = dib + sizeof(BITMAPINFOHEADER);
+
+/*---------------------------------------------------------------------------
+ Fill in background color (black by default); data are in BGR order.
+ ---------------------------------------------------------------------------*/
+
+ for (j = 0; j < image_height; ++j) {
+ dest = wimage_data + j*wimage_rowbytes;
+ for (i = image_width; i > 0; --i) {
+ *dest++ = bg_blue;
+ *dest++ = bg_green;
+ *dest++ = bg_red;
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Set the window parameters.
+ ---------------------------------------------------------------------------*/
+
+ memset(&wndclass, 0, sizeof(wndclass));
+
+ wndclass.cbSize = sizeof(wndclass);
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = rpng_win_wndproc;
+ wndclass.hInstance = hInst;
+ wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = progname;
+ wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+
+ RegisterClassEx(&wndclass);
+
+/*---------------------------------------------------------------------------
+ Finally, create the window.
+ ---------------------------------------------------------------------------*/
+
+ extra_width = 2*(GetSystemMetrics(SM_CXBORDER) +
+ GetSystemMetrics(SM_CXDLGFRAME));
+ extra_height = 2*(GetSystemMetrics(SM_CYBORDER) +
+ GetSystemMetrics(SM_CYDLGFRAME)) +
+ GetSystemMetrics(SM_CYCAPTION);
+
+ global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, image_width+extra_width,
+ image_height+extra_height, NULL, NULL, hInst, NULL);
+
+ ShowWindow(global_hwnd, showmode);
+ UpdateWindow(global_hwnd);
+
+ return 0;
+
+} /* end function rpng_win_create_window() */
+
+
+
+
+
+static int rpng_win_display_image()
+{
+ uch *src, *dest;
+ uch r, g, b, a;
+ ulg i, row, lastrow;
+ RECT rect;
+
+
+ Trace((stderr, "beginning display loop (image_channels == %d)\n",
+ image_channels))
+ Trace((stderr, "(width = %ld, rowbytes = %ld, wimage_rowbytes = %d)\n",
+ image_width, image_rowbytes, wimage_rowbytes))
+
+
+/*---------------------------------------------------------------------------
+ Blast image data to buffer. This whole routine takes place before the
+ message loop begins, so there's no real point in any pseudo-progressive
+ display...
+ ---------------------------------------------------------------------------*/
+
+ for (lastrow = row = 0; row < image_height; ++row) {
+ src = image_data + row*image_rowbytes;
+ dest = wimage_data + row*wimage_rowbytes;
+ if (image_channels == 3) {
+ for (i = image_width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ *dest++ = b;
+ *dest++ = g; /* note reverse order */
+ *dest++ = r;
+ }
+ } else /* if (image_channels == 4) */ {
+ for (i = image_width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (a == 255) {
+ *dest++ = b;
+ *dest++ = g;
+ *dest++ = r;
+ } else if (a == 0) {
+ *dest++ = bg_blue;
+ *dest++ = bg_green;
+ *dest++ = bg_red;
+ } else {
+ /* this macro (copied from png.h) composites the
+ * foreground and background values and puts the
+ * result into the first argument; there are no
+ * side effects with the first argument */
+ alpha_composite(*dest++, b, a, bg_blue);
+ alpha_composite(*dest++, g, a, bg_green);
+ alpha_composite(*dest++, r, a, bg_red);
+ }
+ }
+ }
+ /* display after every 16 lines */
+ if (((row+1) & 0xf) == 0) {
+ rect.left = 0L;
+ rect.top = (LONG)lastrow;
+ rect.right = (LONG)image_width; /* possibly off by one? */
+ rect.bottom = (LONG)lastrow + 16L; /* possibly off by one? */
+ InvalidateRect(global_hwnd, &rect, FALSE);
+ UpdateWindow(global_hwnd); /* similar to XFlush() */
+ lastrow = row + 1;
+ }
+ }
+
+ Trace((stderr, "calling final image-flush routine\n"))
+ if (lastrow < image_height) {
+ rect.left = 0L;
+ rect.top = (LONG)lastrow;
+ rect.right = (LONG)image_width; /* possibly off by one? */
+ rect.bottom = (LONG)image_height; /* possibly off by one? */
+ InvalidateRect(global_hwnd, &rect, FALSE);
+ UpdateWindow(global_hwnd); /* similar to XFlush() */
+ }
+
+/*
+ last param determines whether or not background is wiped before paint
+ InvalidateRect(global_hwnd, NULL, TRUE);
+ UpdateWindow(global_hwnd);
+ */
+
+ return 0;
+}
+
+
+
+
+
+static void rpng_win_cleanup()
+{
+ if (image_data) {
+ free(image_data);
+ image_data = NULL;
+ }
+
+ if (dib) {
+ free(dib);
+ dib = NULL;
+ }
+}
+
+
+
+
+
+LRESULT CALLBACK rpng_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ int rc;
+
+ switch (iMsg) {
+ case WM_CREATE:
+ /* one-time processing here, if any */
+ return 0;
+
+ case WM_PAINT:
+ hdc = BeginPaint(hwnd, &ps);
+ /* dest */
+ rc = StretchDIBits(hdc, 0, 0, image_width, image_height,
+ /* source */
+ 0, 0, image_width, image_height,
+ wimage_data, (BITMAPINFO *)bmih,
+ /* iUsage: no clue */
+ 0, SRCCOPY);
+ EndPaint(hwnd, &ps);
+ return 0;
+
+ /* wait for the user to tell us when to quit */
+ case WM_CHAR:
+ switch (wP) { /* only need one, so ignore repeat count */
+ case 'q':
+ case 'Q':
+ case 0x1B: /* Esc key */
+ PostQuitMessage(0);
+ }
+ return 0;
+
+ case WM_LBUTTONDOWN: /* another way of quitting */
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, iMsg, wP, lP);
+}
diff --git a/contrib/gregbook/rpng-x.c b/contrib/gregbook/rpng-x.c
new file mode 100644
index 0000000..0a98170
--- /dev/null
+++ b/contrib/gregbook/rpng-x.c
@@ -0,0 +1,904 @@
+/*---------------------------------------------------------------------------
+
+ rpng - simple PNG display program rpng-x.c
+
+ This program decodes and displays PNG images, with gamma correction and
+ optionally with a user-specified background color (in case the image has
+ transparency). It is very nearly the most basic PNG viewer possible.
+ This version is for the X Window System (tested by author under Unix and
+ by Martin Zinser under OpenVMS; may work under OS/2 with some tweaking).
+
+ to do:
+ - 8-bit (colormapped) X support
+ - use %.1023s to simplify truncation of title-bar string?
+
+ ---------------------------------------------------------------------------
+
+ Changelog:
+ - 1.01: initial public release
+ - 1.02: modified to allow abbreviated options; fixed long/ulong mis-
+ match; switched to png_jmpbuf() macro
+ - 1.10: added support for non-default visuals; fixed X pixel-conversion
+ - 1.11: added extra set of parentheses to png_jmpbuf() macro; fixed
+ command-line parsing bug
+ - 1.12: fixed some small X memory leaks (thanks to François Petitjean)
+ - 1.13: fixed XFreeGC() crash bug (thanks to Patrick Welche)
+ - 1.14: added support for X resources (thanks to Gerhard Niklasch)
+ - 2.00: dual-licensed (added GNU GPL)
+ - 2.01: fixed improper display of usage screen on PNG error(s)
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#define PROGNAME "rpng-x"
+#define LONGNAME "Simple PNG Viewer for X"
+#define VERSION "2.01 of 16 March 2008"
+#define RESNAME "rpng" /* our X resource application name */
+#define RESCLASS "Rpng" /* our X resource class name */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/keysym.h>
+
+/* #define DEBUG : this enables the Trace() macros */
+
+#include "readpng.h" /* typedefs, common macros, readpng prototypes */
+
+
+/* could just include png.h, but this macro is the only thing we need
+ * (name and typedefs changed to local versions); note that side effects
+ * only happen with alpha (which could easily be avoided with
+ * "ush acopy = (alpha);") */
+
+#define alpha_composite(composite, fg, alpha, bg) { \
+ ush temp = ((ush)(fg)*(ush)(alpha) + \
+ (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
+ (composite) = (uch)((temp + (temp >> 8)) >> 8); \
+}
+
+
+/* local prototypes */
+static int rpng_x_create_window(void);
+static int rpng_x_display_image(void);
+static void rpng_x_cleanup(void);
+static int rpng_x_msb(ulg u32val);
+
+
+static char titlebar[1024], *window_name = titlebar;
+static char *appname = LONGNAME;
+static char *icon_name = PROGNAME;
+static char *res_name = RESNAME;
+static char *res_class = RESCLASS;
+static char *filename;
+static FILE *infile;
+
+static char *bgstr;
+static uch bg_red=0, bg_green=0, bg_blue=0;
+
+static double display_exponent;
+
+static ulg image_width, image_height, image_rowbytes;
+static int image_channels;
+static uch *image_data;
+
+/* X-specific variables */
+static char *displayname;
+static XImage *ximage;
+static Display *display;
+static int depth;
+static Visual *visual;
+static XVisualInfo *visual_list;
+static int RShift, GShift, BShift;
+static ulg RMask, GMask, BMask;
+static Window window;
+static GC gc;
+static Colormap colormap;
+
+static int have_nondefault_visual = FALSE;
+static int have_colormap = FALSE;
+static int have_window = FALSE;
+static int have_gc = FALSE;
+/*
+ulg numcolors=0, pixels[256];
+ush reds[256], greens[256], blues[256];
+ */
+
+
+
+
+int main(int argc, char **argv)
+{
+#ifdef sgi
+ char tmpline[80];
+#endif
+ char *p;
+ int rc, alen, flen;
+ int error = 0;
+ int have_bg = FALSE;
+ double LUT_exponent; /* just the lookup table */
+ double CRT_exponent = 2.2; /* just the monitor */
+ double default_display_exponent; /* whole display system */
+ XEvent e;
+ KeySym k;
+
+
+ displayname = (char *)NULL;
+ filename = (char *)NULL;
+
+
+ /* First set the default value for our display-system exponent, i.e.,
+ * the product of the CRT exponent and the exponent corresponding to
+ * the frame-buffer's lookup table (LUT), if any. This is not an
+ * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
+ * ones), but it should cover 99% of the current possibilities. */
+
+#if defined(NeXT)
+ LUT_exponent = 1.0 / 2.2;
+ /*
+ if (some_next_function_that_returns_gamma(&next_gamma))
+ LUT_exponent = 1.0 / next_gamma;
+ */
+#elif defined(sgi)
+ LUT_exponent = 1.0 / 1.7;
+ /* there doesn't seem to be any documented function to get the
+ * "gamma" value, so we do it the hard way */
+ infile = fopen("/etc/config/system.glGammaVal", "r");
+ if (infile) {
+ double sgi_gamma;
+
+ fgets(tmpline, 80, infile);
+ fclose(infile);
+ sgi_gamma = atof(tmpline);
+ if (sgi_gamma > 0.0)
+ LUT_exponent = 1.0 / sgi_gamma;
+ }
+#elif defined(Macintosh)
+ LUT_exponent = 1.8 / 2.61;
+ /*
+ if (some_mac_function_that_returns_gamma(&mac_gamma))
+ LUT_exponent = mac_gamma / 2.61;
+ */
+#else
+ LUT_exponent = 1.0; /* assume no LUT: most PCs */
+#endif
+
+ /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
+ default_display_exponent = LUT_exponent * CRT_exponent;
+
+
+ /* If the user has set the SCREEN_GAMMA environment variable as suggested
+ * (somewhat imprecisely) in the libpng documentation, use that; otherwise
+ * use the default value we just calculated. Either way, the user may
+ * override this via a command-line option. */
+
+ if ((p = getenv("SCREEN_GAMMA")) != NULL)
+ display_exponent = atof(p);
+ else
+ display_exponent = default_display_exponent;
+
+
+ /* Now parse the command line for options and the PNG filename. */
+
+ while (*++argv && !error) {
+ if (!strncmp(*argv, "-display", 2)) {
+ if (!*++argv)
+ ++error;
+ else
+ displayname = *argv;
+ } else if (!strncmp(*argv, "-gamma", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ display_exponent = atof(*argv);
+ if (display_exponent <= 0.0)
+ ++error;
+ }
+ } else if (!strncmp(*argv, "-bgcolor", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ bgstr = *argv;
+ if (strlen(bgstr) != 7 || bgstr[0] != '#')
+ ++error;
+ else
+ have_bg = TRUE;
+ }
+ } else {
+ if (**argv != '-') {
+ filename = *argv;
+ if (argv[1]) /* shouldn't be any more args after filename */
+ ++error;
+ } else
+ ++error; /* not expecting any other options */
+ }
+ }
+
+ if (!filename)
+ ++error;
+
+
+ /* print usage screen if any errors up to this point */
+
+ if (error) {
+ fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname);
+ readpng_version_info();
+ fprintf(stderr, "\n"
+ "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg] file.png\n"
+ " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
+ " exp \ttransfer-function exponent (``gamma'') of the display\n"
+ "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
+ "\t\t to the product of the lookup-table exponent (varies)\n"
+ "\t\t and the CRT exponent (usually 2.2); must be positive\n"
+ " bg \tdesired background color in 7-character hex RGB format\n"
+ "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
+ "\t\t used with transparent images\n"
+ "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
+ "is displayed) to quit.\n"
+ "\n", PROGNAME, default_display_exponent);
+ exit(1);
+ }
+
+
+ if (!(infile = fopen(filename, "rb"))) {
+ fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
+ ++error;
+ } else {
+ if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
+ switch (rc) {
+ case 1:
+ fprintf(stderr, PROGNAME
+ ": [%s] is not a PNG file: incorrect signature\n",
+ filename);
+ break;
+ case 2:
+ fprintf(stderr, PROGNAME
+ ": [%s] has bad IHDR (libpng longjmp)\n", filename);
+ break;
+ case 4:
+ fprintf(stderr, PROGNAME ": insufficient memory\n");
+ break;
+ default:
+ fprintf(stderr, PROGNAME
+ ": unknown readpng_init() error\n");
+ break;
+ }
+ ++error;
+ } else {
+ display = XOpenDisplay(displayname);
+ if (!display) {
+ readpng_cleanup(TRUE);
+ fprintf(stderr, PROGNAME ": can't open X display [%s]\n",
+ displayname? displayname : "default");
+ ++error;
+ }
+ }
+ if (error)
+ fclose(infile);
+ }
+
+
+ if (error) {
+ fprintf(stderr, PROGNAME ": aborting.\n");
+ exit(2);
+ }
+
+
+ /* set the title-bar string, but make sure buffer doesn't overflow */
+
+ alen = strlen(appname);
+ flen = strlen(filename);
+ if (alen + flen + 3 > 1023)
+ sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
+ else
+ sprintf(titlebar, "%s: %s", appname, filename);
+
+
+ /* if the user didn't specify a background color on the command line,
+ * check for one in the PNG file--if not, the initialized values of 0
+ * (black) will be used */
+
+ if (have_bg) {
+ unsigned r, g, b; /* this approach quiets compiler warnings */
+
+ sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
+ bg_red = (uch)r;
+ bg_green = (uch)g;
+ bg_blue = (uch)b;
+ } else if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1) {
+ readpng_cleanup(TRUE);
+ fprintf(stderr, PROGNAME
+ ": libpng error while checking for background color\n");
+ exit(2);
+ }
+
+
+ /* do the basic X initialization stuff, make the window and fill it
+ * with the background color */
+
+ if (rpng_x_create_window())
+ exit(2);
+
+
+ /* decode the image, all at once */
+
+ Trace((stderr, "calling readpng_get_image()\n"))
+ image_data = readpng_get_image(display_exponent, &image_channels,
+ &image_rowbytes);
+ Trace((stderr, "done with readpng_get_image()\n"))
+
+
+ /* done with PNG file, so clean up to minimize memory usage (but do NOT
+ * nuke image_data!) */
+
+ readpng_cleanup(FALSE);
+ fclose(infile);
+
+ if (!image_data) {
+ fprintf(stderr, PROGNAME ": unable to decode PNG image\n");
+ exit(3);
+ }
+
+
+ /* display image (composite with background if requested) */
+
+ Trace((stderr, "calling rpng_x_display_image()\n"))
+ if (rpng_x_display_image()) {
+ free(image_data);
+ exit(4);
+ }
+ Trace((stderr, "done with rpng_x_display_image()\n"))
+
+
+ /* wait for the user to tell us when to quit */
+
+ printf(
+ "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
+ fflush(stdout);
+
+ do
+ XNextEvent(display, &e);
+ while (!(e.type == ButtonPress && e.xbutton.button == Button1) &&
+ !(e.type == KeyPress && /* v--- or 1 for shifted keys */
+ ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape) ));
+
+
+ /* OK, we're done: clean up all image and X resources and go away */
+
+ rpng_x_cleanup();
+
+ return 0;
+}
+
+
+
+
+
+static int rpng_x_create_window(void)
+{
+ uch *xdata;
+ int need_colormap = FALSE;
+ int screen, pad;
+ ulg bg_pixel = 0L;
+ ulg attrmask;
+ Window root;
+ XEvent e;
+ XGCValues gcvalues;
+ XSetWindowAttributes attr;
+ XTextProperty windowName, *pWindowName = &windowName;
+ XTextProperty iconName, *pIconName = &iconName;
+ XVisualInfo visual_info;
+ XSizeHints *size_hints;
+ XWMHints *wm_hints;
+ XClassHint *class_hints;
+
+
+ screen = DefaultScreen(display);
+ depth = DisplayPlanes(display, screen);
+ root = RootWindow(display, screen);
+
+#ifdef DEBUG
+ XSynchronize(display, True);
+#endif
+
+#if 0
+/* GRR: add 8-bit support */
+ if (/* depth != 8 && */ depth != 16 && depth != 24 && depth != 32) {
+ fprintf(stderr,
+ "screen depth %d not supported (only 16-, 24- or 32-bit TrueColor)\n",
+ depth);
+ return 2;
+ }
+
+ XMatchVisualInfo(display, screen, depth,
+ (depth == 8)? PseudoColor : TrueColor, &visual_info);
+ visual = visual_info.visual;
+#else
+ if (depth != 16 && depth != 24 && depth != 32) {
+ int visuals_matched = 0;
+
+ Trace((stderr, "default depth is %d: checking other visuals\n",
+ depth))
+
+ /* 24-bit first */
+ visual_info.screen = screen;
+ visual_info.depth = 24;
+ visual_list = XGetVisualInfo(display,
+ VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
+ if (visuals_matched == 0) {
+/* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
+ fprintf(stderr, "default screen depth %d not supported, and no"
+ " 24-bit visuals found\n", depth);
+ return 2;
+ }
+ Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
+ visuals_matched))
+ visual = visual_list[0].visual;
+ depth = visual_list[0].depth;
+/*
+ colormap_size = visual_list[0].colormap_size;
+ visual_class = visual->class;
+ visualID = XVisualIDFromVisual(visual);
+ */
+ have_nondefault_visual = TRUE;
+ need_colormap = TRUE;
+ } else {
+ XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
+ visual = visual_info.visual;
+ }
+#endif
+
+ RMask = visual->red_mask;
+ GMask = visual->green_mask;
+ BMask = visual->blue_mask;
+
+/* GRR: add/check 8-bit support */
+ if (depth == 8 || need_colormap) {
+ colormap = XCreateColormap(display, root, visual, AllocNone);
+ if (!colormap) {
+ fprintf(stderr, "XCreateColormap() failed\n");
+ return 2;
+ }
+ have_colormap = TRUE;
+ }
+ if (depth == 15 || depth == 16) {
+ RShift = 15 - rpng_x_msb(RMask); /* these are right-shifts */
+ GShift = 15 - rpng_x_msb(GMask);
+ BShift = 15 - rpng_x_msb(BMask);
+ } else if (depth > 16) {
+#define NO_24BIT_MASKS
+#ifdef NO_24BIT_MASKS
+ RShift = rpng_x_msb(RMask) - 7; /* these are left-shifts */
+ GShift = rpng_x_msb(GMask) - 7;
+ BShift = rpng_x_msb(BMask) - 7;
+#else
+ RShift = 7 - rpng_x_msb(RMask); /* these are right-shifts, too */
+ GShift = 7 - rpng_x_msb(GMask);
+ BShift = 7 - rpng_x_msb(BMask);
+#endif
+ }
+ if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
+ fprintf(stderr, "rpng internal logic error: negative X shift(s)!\n");
+ return 2;
+ }
+
+/*---------------------------------------------------------------------------
+ Finally, create the window.
+ ---------------------------------------------------------------------------*/
+
+ attr.backing_store = Always;
+ attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
+ attrmask = CWBackingStore | CWEventMask;
+ if (have_nondefault_visual) {
+ attr.colormap = colormap;
+ attr.background_pixel = 0;
+ attr.border_pixel = 1;
+ attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
+ }
+
+ window = XCreateWindow(display, root, 0, 0, image_width, image_height, 0,
+ depth, InputOutput, visual, attrmask, &attr);
+
+ if (window == None) {
+ fprintf(stderr, "XCreateWindow() failed\n");
+ return 2;
+ } else
+ have_window = TRUE;
+
+ if (depth == 8)
+ XSetWindowColormap(display, window, colormap);
+
+ if (!XStringListToTextProperty(&window_name, 1, pWindowName))
+ pWindowName = NULL;
+ if (!XStringListToTextProperty(&icon_name, 1, pIconName))
+ pIconName = NULL;
+
+ /* OK if any hints allocation fails; XSetWMProperties() allows NULLs */
+
+ if ((size_hints = XAllocSizeHints()) != NULL) {
+ /* window will not be resizable */
+ size_hints->flags = PMinSize | PMaxSize;
+ size_hints->min_width = size_hints->max_width = (int)image_width;
+ size_hints->min_height = size_hints->max_height = (int)image_height;
+ }
+
+ if ((wm_hints = XAllocWMHints()) != NULL) {
+ wm_hints->initial_state = NormalState;
+ wm_hints->input = True;
+ /* wm_hints->icon_pixmap = icon_pixmap; */
+ wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ;
+ }
+
+ if ((class_hints = XAllocClassHint()) != NULL) {
+ class_hints->res_name = res_name;
+ class_hints->res_class = res_class;
+ }
+
+ XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
+ size_hints, wm_hints, class_hints);
+
+ /* various properties and hints no longer needed; free memory */
+ if (pWindowName)
+ XFree(pWindowName->value);
+ if (pIconName)
+ XFree(pIconName->value);
+ if (size_hints)
+ XFree(size_hints);
+ if (wm_hints)
+ XFree(wm_hints);
+ if (class_hints)
+ XFree(class_hints);
+
+ XMapWindow(display, window);
+
+ gc = XCreateGC(display, window, 0, &gcvalues);
+ have_gc = TRUE;
+
+/*---------------------------------------------------------------------------
+ Fill window with the specified background color.
+ ---------------------------------------------------------------------------*/
+
+ if (depth == 24 || depth == 32) {
+ bg_pixel = ((ulg)bg_red << RShift) |
+ ((ulg)bg_green << GShift) |
+ ((ulg)bg_blue << BShift);
+ } else if (depth == 16) {
+ bg_pixel = ((((ulg)bg_red << 8) >> RShift) & RMask) |
+ ((((ulg)bg_green << 8) >> GShift) & GMask) |
+ ((((ulg)bg_blue << 8) >> BShift) & BMask);
+ } else /* depth == 8 */ {
+
+ /* GRR: add 8-bit support */
+
+ }
+
+ XSetForeground(display, gc, bg_pixel);
+ XFillRectangle(display, window, gc, 0, 0, image_width, image_height);
+
+/*---------------------------------------------------------------------------
+ Wait for first Expose event to do any drawing, then flush.
+ ---------------------------------------------------------------------------*/
+
+ do
+ XNextEvent(display, &e);
+ while (e.type != Expose || e.xexpose.count);
+
+ XFlush(display);
+
+/*---------------------------------------------------------------------------
+ Allocate memory for the X- and display-specific version of the image.
+ ---------------------------------------------------------------------------*/
+
+ if (depth == 24 || depth == 32) {
+ xdata = (uch *)malloc(4*image_width*image_height);
+ pad = 32;
+ } else if (depth == 16) {
+ xdata = (uch *)malloc(2*image_width*image_height);
+ pad = 16;
+ } else /* depth == 8 */ {
+ xdata = (uch *)malloc(image_width*image_height);
+ pad = 8;
+ }
+
+ if (!xdata) {
+ fprintf(stderr, PROGNAME ": unable to allocate image memory\n");
+ return 4;
+ }
+
+ ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
+ (char *)xdata, image_width, image_height, pad, 0);
+
+ if (!ximage) {
+ fprintf(stderr, PROGNAME ": XCreateImage() failed\n");
+ free(xdata);
+ return 3;
+ }
+
+ /* to avoid testing the byte order every pixel (or doubling the size of
+ * the drawing routine with a giant if-test), we arbitrarily set the byte
+ * order to MSBFirst and let Xlib worry about inverting things on little-
+ * endian machines (like Linux/x86, old VAXen, etc.)--this is not the most
+ * efficient approach (the giant if-test would be better), but in the
+ * interest of clarity, we take the easy way out... */
+
+ ximage->byte_order = MSBFirst;
+
+ return 0;
+
+} /* end function rpng_x_create_window() */
+
+
+
+
+
+static int rpng_x_display_image(void)
+{
+ uch *src;
+ char *dest;
+ uch r, g, b, a;
+ ulg i, row, lastrow = 0;
+ ulg pixel;
+ int ximage_rowbytes = ximage->bytes_per_line;
+/* int bpp = ximage->bits_per_pixel; */
+
+
+ Trace((stderr, "beginning display loop (image_channels == %d)\n",
+ image_channels))
+ Trace((stderr, " (width = %ld, rowbytes = %ld, ximage_rowbytes = %d)\n",
+ image_width, image_rowbytes, ximage_rowbytes))
+ Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel))
+ Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst?
+ "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
+
+ if (depth == 24 || depth == 32) {
+ ulg red, green, blue;
+
+ for (lastrow = row = 0; row < image_height; ++row) {
+ src = image_data + row*image_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ if (image_channels == 3) {
+ for (i = image_width; i > 0; --i) {
+ red = *src++;
+ green = *src++;
+ blue = *src++;
+#ifdef NO_24BIT_MASKS
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ /* GRR BUG: this assumes bpp == 32, but may be 24: */
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+#else
+ red = (RShift < 0)? red << (-RShift) : red >> RShift;
+ green = (GShift < 0)? green << (-GShift) : green >> GShift;
+ blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
+ pixel = (red & RMask) | (green & GMask) | (blue & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+#endif
+ }
+ } else /* if (image_channels == 4) */ {
+ for (i = image_width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (a == 255) {
+ red = r;
+ green = g;
+ blue = b;
+ } else if (a == 0) {
+ red = bg_red;
+ green = bg_green;
+ blue = bg_blue;
+ } else {
+ /* this macro (from png.h) composites the foreground
+ * and background values and puts the result into the
+ * first argument */
+ alpha_composite(red, r, a, bg_red);
+ alpha_composite(green, g, a, bg_green);
+ alpha_composite(blue, b, a, bg_blue);
+ }
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+ /* display after every 16 lines */
+ if (((row+1) & 0xf) == 0) {
+ XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
+ (int)lastrow, image_width, 16);
+ XFlush(display);
+ lastrow = row + 1;
+ }
+ }
+
+ } else if (depth == 16) {
+ ush red, green, blue;
+
+ for (lastrow = row = 0; row < image_height; ++row) {
+ src = image_data + row*image_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ if (image_channels == 3) {
+ for (i = image_width; i > 0; --i) {
+ red = ((ush)(*src) << 8);
+ ++src;
+ green = ((ush)(*src) << 8);
+ ++src;
+ blue = ((ush)(*src) << 8);
+ ++src;
+ pixel = ((red >> RShift) & RMask) |
+ ((green >> GShift) & GMask) |
+ ((blue >> BShift) & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ } else /* if (image_channels == 4) */ {
+ for (i = image_width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (a == 255) {
+ red = ((ush)r << 8);
+ green = ((ush)g << 8);
+ blue = ((ush)b << 8);
+ } else if (a == 0) {
+ red = ((ush)bg_red << 8);
+ green = ((ush)bg_green << 8);
+ blue = ((ush)bg_blue << 8);
+ } else {
+ /* this macro (from png.h) composites the foreground
+ * and background values and puts the result back into
+ * the first argument (== fg byte here: safe) */
+ alpha_composite(r, r, a, bg_red);
+ alpha_composite(g, g, a, bg_green);
+ alpha_composite(b, b, a, bg_blue);
+ red = ((ush)r << 8);
+ green = ((ush)g << 8);
+ blue = ((ush)b << 8);
+ }
+ pixel = ((red >> RShift) & RMask) |
+ ((green >> GShift) & GMask) |
+ ((blue >> BShift) & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+ /* display after every 16 lines */
+ if (((row+1) & 0xf) == 0) {
+ XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
+ (int)lastrow, image_width, 16);
+ XFlush(display);
+ lastrow = row + 1;
+ }
+ }
+
+ } else /* depth == 8 */ {
+
+ /* GRR: add 8-bit support */
+
+ }
+
+ Trace((stderr, "calling final XPutImage()\n"))
+ if (lastrow < image_height) {
+ XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
+ (int)lastrow, image_width, image_height-lastrow);
+ XFlush(display);
+ }
+
+ return 0;
+}
+
+
+
+
+static void rpng_x_cleanup(void)
+{
+ if (image_data) {
+ free(image_data);
+ image_data = NULL;
+ }
+
+ if (ximage) {
+ if (ximage->data) {
+ free(ximage->data); /* we allocated it, so we free it */
+ ximage->data = (char *)NULL; /* instead of XDestroyImage() */
+ }
+ XDestroyImage(ximage);
+ ximage = NULL;
+ }
+
+ if (have_gc)
+ XFreeGC(display, gc);
+
+ if (have_window)
+ XDestroyWindow(display, window);
+
+ if (have_colormap)
+ XFreeColormap(display, colormap);
+
+ if (have_nondefault_visual)
+ XFree(visual_list);
+}
+
+
+
+
+
+static int rpng_x_msb(ulg u32val)
+{
+ int i;
+
+ for (i = 31; i >= 0; --i) {
+ if (u32val & 0x80000000L)
+ break;
+ u32val <<= 1;
+ }
+ return i;
+}
diff --git a/contrib/gregbook/rpng2-win.c b/contrib/gregbook/rpng2-win.c
new file mode 100644
index 0000000..9f7ad78
--- /dev/null
+++ b/contrib/gregbook/rpng2-win.c
@@ -0,0 +1,1225 @@
+/*---------------------------------------------------------------------------
+
+ rpng2 - progressive-model PNG display program rpng2-win.c
+
+ This program decodes and displays PNG files progressively, as if it were
+ a web browser (though the front end is only set up to read from files).
+ It supports gamma correction, user-specified background colors, and user-
+ specified background patterns (for transparent images). This version is
+ for 32-bit Windows; it may compile under 16-bit Windows with a little
+ tweaking (or maybe not). Thanks to Adam Costello and Pieter S. van der
+ Meulen for the "diamond" and "radial waves" patterns, respectively.
+
+ to do (someday, maybe):
+ - handle quoted command-line args (especially filenames with spaces)
+ - finish resizable checkerboard-gradient (sizes 4-128?)
+ - use %.1023s to simplify truncation of title-bar string?
+ - have minimum window width: oh well
+
+ ---------------------------------------------------------------------------
+
+ Changelog:
+ - 1.01: initial public release
+ - 1.02: fixed cut-and-paste error in usage screen (oops...)
+ - 1.03: modified to allow abbreviated options
+ - 1.04: removed bogus extra argument from usage fprintf() [Glenn R-P?];
+ fixed command-line parsing bug
+ - 1.10: enabled "message window"/console (thanks to David Geldreich)
+ - 1.20: added runtime MMX-enabling/disabling and new -mmx* options
+ - 1.21: made minor tweak to usage screen to fit within 25-line console
+ - 1.22: added AMD64/EM64T support (__x86_64__)
+ - 2.00: dual-licensed (added GNU GPL)
+ - 2.01: fixed 64-bit typo in readpng2.c
+ - 2.02: fixed improper display of usage screen on PNG error(s); fixed
+ unexpected-EOF and file-read-error cases
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#define PROGNAME "rpng2-win"
+#define LONGNAME "Progressive PNG Viewer for Windows"
+#define VERSION "2.02 of 16 March 2008"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h> /* for jmpbuf declaration in readpng2.h */
+#include <time.h>
+#include <math.h> /* only for PvdM background code */
+#include <windows.h>
+#include <conio.h> /* only for _getch() */
+
+/* all for PvdM background code: */
+#ifndef PI
+# define PI 3.141592653589793238
+#endif
+#define PI_2 (PI*0.5)
+#define INV_PI_360 (360.0 / PI)
+#define MAX(a,b) (a>b?a:b)
+#define MIN(a,b) (a<b?a:b)
+#define CLIP(a,min,max) MAX(min,MIN((a),max))
+#define ABS(a) ((a)<0?-(a):(a))
+#define CLIP8P(c) MAX(0,(MIN((c),255))) /* 8-bit pos. integer (uch) */
+#define ROUNDF(f) ((int)(f + 0.5))
+
+#define rgb1_max bg_freq
+#define rgb1_min bg_gray
+#define rgb2_max bg_bsat
+#define rgb2_min bg_brot
+
+/* #define DEBUG */ /* this enables the Trace() macros */
+
+#include "readpng2.h" /* typedefs, common macros, readpng2 prototypes */
+
+
+/* could just include png.h, but this macro is the only thing we need
+ * (name and typedefs changed to local versions); note that side effects
+ * only happen with alpha (which could easily be avoided with
+ * "ush acopy = (alpha);") */
+
+#define alpha_composite(composite, fg, alpha, bg) { \
+ ush temp = ((ush)(fg)*(ush)(alpha) + \
+ (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
+ (composite) = (uch)((temp + (temp >> 8)) >> 8); \
+}
+
+
+#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this
+ * block size corresponds roughly to a download
+ * speed 10% faster than theoretical 33.6K maximum
+ * (assuming 8 data bits, 1 stop bit and no other
+ * overhead) */
+
+/* local prototypes */
+static void rpng2_win_init(void);
+static int rpng2_win_create_window(void);
+static int rpng2_win_load_bg_image(void);
+static void rpng2_win_display_row(ulg row);
+static void rpng2_win_finish_display(void);
+static void rpng2_win_cleanup(void);
+LRESULT CALLBACK rpng2_win_wndproc(HWND, UINT, WPARAM, LPARAM);
+
+
+static char titlebar[1024];
+static char *progname = PROGNAME;
+static char *appname = LONGNAME;
+static char *filename;
+static FILE *infile;
+
+static mainprog_info rpng2_info;
+
+static uch inbuf[INBUFSIZE];
+static int incount;
+
+static int pat = 6; /* must be less than num_bgpat */
+static int bg_image = 0;
+static int bgscale = 16;
+static ulg bg_rowbytes;
+static uch *bg_data;
+
+static struct rgb_color {
+ uch r, g, b;
+} rgb[] = {
+ { 0, 0, 0}, /* 0: black */
+ {255, 255, 255}, /* 1: white */
+ {173, 132, 57}, /* 2: tan */
+ { 64, 132, 0}, /* 3: medium green */
+ {189, 117, 1}, /* 4: gold */
+ {253, 249, 1}, /* 5: yellow */
+ { 0, 0, 255}, /* 6: blue */
+ { 0, 0, 120}, /* 7: medium blue */
+ {255, 0, 255}, /* 8: magenta */
+ { 64, 0, 64}, /* 9: dark magenta */
+ {255, 0, 0}, /* 10: red */
+ { 64, 0, 0}, /* 11: dark red */
+ {255, 127, 0}, /* 12: orange */
+ {192, 96, 0}, /* 13: darker orange */
+ { 24, 60, 0}, /* 14: dark green-yellow */
+ { 85, 125, 200} /* 15: ice blue */
+};
+/* not used for now, but should be for error-checking:
+static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
+ */
+
+/*
+ This whole struct is a fairly cheesy way to keep the number of
+ command-line options to a minimum. The radial-waves background
+ type is a particularly poor fit to the integer elements of the
+ struct...but a few macros and a little fixed-point math will do
+ wonders for ya.
+
+ type bits:
+ F E D C B A 9 8 7 6 5 4 3 2 1 0
+ | | | | |
+ | | +-+-+-- 0 = sharp-edged checkerboard
+ | | 1 = soft diamonds
+ | | 2 = radial waves
+ | | 3-7 = undefined
+ | +-- gradient #2 inverted?
+ +-- alternating columns inverted?
+ */
+static struct background_pattern {
+ ush type;
+ int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */
+ int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/
+} bg[] = {
+ {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */
+ {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */
+ {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */
+ {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */
+ {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */
+ {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */
+ {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */
+ {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */
+ {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */
+ {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */
+ {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */
+ {1, 3,0, 0,0}, /* diamonds: medium green vs. black */
+ {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */
+ {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */
+ {2, 16, 256, 100, 250}, /* radial: very tight spiral */
+ {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */
+};
+static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
+
+
+/* Windows-specific global variables (could go in struct, but messy...) */
+static ulg wimage_rowbytes;
+static uch *dib;
+static uch *wimage_data;
+static BITMAPINFOHEADER *bmih;
+
+static HWND global_hwnd;
+static HINSTANCE global_hInst;
+static int global_showmode;
+
+
+
+
+int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR cmd, int showmode)
+{
+ char *args[1024]; /* arbitrary limit, but should suffice */
+ char **argv = args;
+ char *p, *q, *bgstr = NULL;
+ int argc = 0;
+ int rc, alen, flen;
+ int error = 0;
+ int timing = FALSE;
+ int have_bg = FALSE;
+ double LUT_exponent; /* just the lookup table */
+ double CRT_exponent = 2.2; /* just the monitor */
+ double default_display_exponent; /* whole display system */
+ MSG msg;
+
+
+ /* First initialize a few things, just to be sure--memset takes care of
+ * default background color (black), booleans (FALSE), pointers (NULL),
+ * etc. */
+
+ global_hInst = hInst;
+ global_showmode = showmode;
+ filename = (char *)NULL;
+ memset(&rpng2_info, 0, sizeof(mainprog_info));
+
+
+ /* Next reenable console output, which normally goes to the bit bucket
+ * for windowed apps. Closing the console window will terminate the
+ * app. Thanks to David.Geldreich@realviz.com for supplying the magical
+ * incantation. */
+
+ AllocConsole();
+ freopen("CONOUT$", "a", stderr);
+ freopen("CONOUT$", "a", stdout);
+
+
+ /* Set the default value for our display-system exponent, i.e., the
+ * product of the CRT exponent and the exponent corresponding to
+ * the frame-buffer's lookup table (LUT), if any. This is not an
+ * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
+ * ones), but it should cover 99% of the current possibilities. And
+ * yes, these ifdefs are completely wasted in a Windows program... */
+
+#if defined(NeXT)
+ /* third-party utilities can modify the default LUT exponent */
+ LUT_exponent = 1.0 / 2.2;
+ /*
+ if (some_next_function_that_returns_gamma(&next_gamma))
+ LUT_exponent = 1.0 / next_gamma;
+ */
+#elif defined(sgi)
+ LUT_exponent = 1.0 / 1.7;
+ /* there doesn't seem to be any documented function to
+ * get the "gamma" value, so we do it the hard way */
+ infile = fopen("/etc/config/system.glGammaVal", "r");
+ if (infile) {
+ double sgi_gamma;
+
+ fgets(tmpline, 80, infile);
+ fclose(infile);
+ sgi_gamma = atof(tmpline);
+ if (sgi_gamma > 0.0)
+ LUT_exponent = 1.0 / sgi_gamma;
+ }
+#elif defined(Macintosh)
+ LUT_exponent = 1.8 / 2.61;
+ /*
+ if (some_mac_function_that_returns_gamma(&mac_gamma))
+ LUT_exponent = mac_gamma / 2.61;
+ */
+#else
+ LUT_exponent = 1.0; /* assume no LUT: most PCs */
+#endif
+
+ /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
+ default_display_exponent = LUT_exponent * CRT_exponent;
+
+
+ /* If the user has set the SCREEN_GAMMA environment variable as suggested
+ * (somewhat imprecisely) in the libpng documentation, use that; otherwise
+ * use the default value we just calculated. Either way, the user may
+ * override this via a command-line option. */
+
+ if ((p = getenv("SCREEN_GAMMA")) != NULL)
+ rpng2_info.display_exponent = atof(p);
+ else
+ rpng2_info.display_exponent = default_display_exponent;
+
+
+ /* Windows really hates command lines, so we have to set up our own argv.
+ * Note that we do NOT bother with quoted arguments here, so don't use
+ * filenames with spaces in 'em! */
+
+ argv[argc++] = PROGNAME;
+ p = cmd;
+ for (;;) {
+ if (*p == ' ')
+ while (*++p == ' ')
+ ;
+ /* now p points at the first non-space after some spaces */
+ if (*p == '\0')
+ break; /* nothing after the spaces: done */
+ argv[argc++] = q = p;
+ while (*q && *q != ' ')
+ ++q;
+ /* now q points at a space or the end of the string */
+ if (*q == '\0')
+ break; /* last argv already terminated; quit */
+ *q = '\0'; /* change space to terminator */
+ p = q + 1;
+ }
+ argv[argc] = NULL; /* terminate the argv array itself */
+
+
+ /* Now parse the command line for options and the PNG filename. */
+
+ while (*++argv && !error) {
+ if (!strncmp(*argv, "-gamma", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ rpng2_info.display_exponent = atof(*argv);
+ if (rpng2_info.display_exponent <= 0.0)
+ ++error;
+ }
+ } else if (!strncmp(*argv, "-bgcolor", 4)) {
+ if (!*++argv)
+ ++error;
+ else {
+ bgstr = *argv;
+ if (strlen(bgstr) != 7 || bgstr[0] != '#')
+ ++error;
+ else {
+ have_bg = TRUE;
+ bg_image = FALSE;
+ }
+ }
+ } else if (!strncmp(*argv, "-bgpat", 4)) {
+ if (!*++argv)
+ ++error;
+ else {
+ pat = atoi(*argv) - 1;
+ if (pat < 0 || pat >= num_bgpat)
+ ++error;
+ else {
+ bg_image = TRUE;
+ have_bg = FALSE;
+ }
+ }
+ } else if (!strncmp(*argv, "-timing", 2)) {
+ timing = TRUE;
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ } else if (!strncmp(*argv, "-nommxfilters", 7)) {
+ rpng2_info.nommxfilters = TRUE;
+ } else if (!strncmp(*argv, "-nommxcombine", 7)) {
+ rpng2_info.nommxcombine = TRUE;
+ } else if (!strncmp(*argv, "-nommxinterlace", 7)) {
+ rpng2_info.nommxinterlace = TRUE;
+ } else if (!strcmp(*argv, "-nommx")) {
+ rpng2_info.nommxfilters = TRUE;
+ rpng2_info.nommxcombine = TRUE;
+ rpng2_info.nommxinterlace = TRUE;
+#endif
+ } else {
+ if (**argv != '-') {
+ filename = *argv;
+ if (argv[1]) /* shouldn't be any more args after filename */
+ ++error;
+ } else
+ ++error; /* not expecting any other options */
+ }
+ }
+
+ if (!filename)
+ ++error;
+
+
+ /* print usage screen if any errors up to this point */
+
+ if (error) {
+ int ch;
+
+ fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname);
+ readpng2_version_info();
+ fprintf(stderr, "\n"
+ "Usage: %s [-gamma exp] [-bgcolor bg | -bgpat pat] [-timing]\n"
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ " %*s [[-nommxfilters] [-nommxcombine] [-nommxinterlace] | -nommx]\n"
+#endif
+ " %*s file.png\n\n"
+ " exp \ttransfer-function exponent (``gamma'') of the display\n"
+ "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
+ "\t\t to the product of the lookup-table exponent (varies)\n"
+ "\t\t and the CRT exponent (usually 2.2); must be positive\n"
+ " bg \tdesired background color in 7-character hex RGB format\n"
+ "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
+ "\t\t used with transparent images; overrides -bgpat option\n"
+ " pat \tdesired background pattern number (1-%d); used with\n"
+ "\t\t transparent images; overrides -bgcolor option\n"
+ " -timing\tenables delay for every block read, to simulate modem\n"
+ "\t\t download of image (~36 Kbps)\n"
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ " -nommx*\tdisable optimized MMX routines for decoding row filters,\n"
+ "\t\t combining rows, and expanding interlacing, respectively\n"
+#endif
+ "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n"
+ "Press Q or Esc to quit this usage screen. ",
+ PROGNAME,
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ (int)strlen(PROGNAME), " ",
+#endif
+ (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat);
+ fflush(stderr);
+ do
+ ch = _getch();
+ while (ch != 'q' && ch != 'Q' && ch != 0x1B);
+ exit(1);
+ }
+
+
+ if (!(infile = fopen(filename, "rb"))) {
+ fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
+ ++error;
+ } else {
+ incount = fread(inbuf, 1, INBUFSIZE, infile);
+ if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
+ fprintf(stderr, PROGNAME
+ ": [%s] is not a PNG file: incorrect signature\n",
+ filename);
+ ++error;
+ } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
+ switch (rc) {
+ case 2:
+ fprintf(stderr, PROGNAME
+ ": [%s] has bad IHDR (libpng longjmp)\n", filename);
+ break;
+ case 4:
+ fprintf(stderr, PROGNAME ": insufficient memory\n");
+ break;
+ default:
+ fprintf(stderr, PROGNAME
+ ": unknown readpng2_init() error\n");
+ break;
+ }
+ ++error;
+ }
+ if (error)
+ fclose(infile);
+ }
+
+
+ if (error) {
+ int ch;
+
+ fprintf(stderr, PROGNAME ": aborting.\n");
+ do
+ ch = _getch();
+ while (ch != 'q' && ch != 'Q' && ch != 0x1B);
+ exit(2);
+ } else {
+ fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname);
+ fprintf(stderr,
+ "\n [console window: closing this window will terminate %s]\n\n",
+ PROGNAME);
+ fflush(stderr);
+ }
+
+
+ /* set the title-bar string, but make sure buffer doesn't overflow */
+
+ alen = strlen(appname);
+ flen = strlen(filename);
+ if (alen + flen + 3 > 1023)
+ sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
+ else
+ sprintf(titlebar, "%s: %s", appname, filename);
+
+
+ /* set some final rpng2_info variables before entering main data loop */
+
+ if (have_bg) {
+ unsigned r, g, b; /* this approach quiets compiler warnings */
+
+ sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
+ rpng2_info.bg_red = (uch)r;
+ rpng2_info.bg_green = (uch)g;
+ rpng2_info.bg_blue = (uch)b;
+ } else
+ rpng2_info.need_bgcolor = TRUE;
+
+ rpng2_info.state = kPreInit;
+ rpng2_info.mainprog_init = rpng2_win_init;
+ rpng2_info.mainprog_display_row = rpng2_win_display_row;
+ rpng2_info.mainprog_finish_display = rpng2_win_finish_display;
+
+
+ /* OK, this is the fun part: call readpng2_decode_data() at the start of
+ * the loop to deal with our first buffer of data (read in above to verify
+ * that the file is a PNG image), then loop through the file and continue
+ * calling the same routine to handle each chunk of data. It in turn
+ * passes the data to libpng, which will invoke one or more of our call-
+ * backs as decoded data become available. We optionally call Sleep() for
+ * one second per iteration to simulate downloading the image via an analog
+ * modem. */
+
+ for (;;) {
+ Trace((stderr, "about to call readpng2_decode_data()\n"))
+ if (readpng2_decode_data(&rpng2_info, inbuf, incount))
+ ++error;
+ Trace((stderr, "done with readpng2_decode_data()\n"))
+
+ if (error || incount != INBUFSIZE || rpng2_info.state == kDone) {
+ if (rpng2_info.state == kDone) {
+ Trace((stderr, "done decoding PNG image\n"))
+ } else if (ferror(infile)) {
+ fprintf(stderr, PROGNAME
+ ": error while reading PNG image file\n");
+ exit(3);
+ } else if (feof(infile)) {
+ fprintf(stderr, PROGNAME ": end of file reached "
+ "(unexpectedly) while reading PNG image file\n");
+ exit(3);
+ } else /* if (error) */ {
+ // will print error message below
+ }
+ break;
+ }
+
+ if (timing)
+ Sleep(1000L);
+
+ incount = fread(inbuf, 1, INBUFSIZE, infile);
+ }
+
+
+ /* clean up PNG stuff and report any decoding errors */
+
+ fclose(infile);
+ Trace((stderr, "about to call readpng2_cleanup()\n"))
+ readpng2_cleanup(&rpng2_info);
+
+ if (error) {
+ fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n");
+ exit(3);
+ }
+
+
+ /* wait for the user to tell us when to quit */
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+
+ /* we're done: clean up all image and Windows resources and go away */
+
+ Trace((stderr, "about to call rpng2_win_cleanup()\n"))
+ rpng2_win_cleanup();
+
+ return msg.wParam;
+}
+
+
+
+
+
+/* this function is called by readpng2_info_callback() in readpng2.c, which
+ * in turn is called by libpng after all of the pre-IDAT chunks have been
+ * read and processed--i.e., we now have enough info to finish initializing */
+
+static void rpng2_win_init()
+{
+ ulg i;
+ ulg rowbytes = rpng2_info.rowbytes;
+
+ Trace((stderr, "beginning rpng2_win_init()\n"))
+ Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes))
+ Trace((stderr, " width = %ld\n", rpng2_info.width))
+ Trace((stderr, " height = %ld\n", rpng2_info.height))
+
+ rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
+ if (!rpng2_info.image_data) {
+ readpng2_cleanup(&rpng2_info);
+ return;
+ }
+
+ rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
+ if (!rpng2_info.row_pointers) {
+ free(rpng2_info.image_data);
+ rpng2_info.image_data = NULL;
+ readpng2_cleanup(&rpng2_info);
+ return;
+ }
+
+ for (i = 0; i < rpng2_info.height; ++i)
+ rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
+
+/*---------------------------------------------------------------------------
+ Do the basic Windows initialization stuff, make the window, and fill it
+ with the user-specified, file-specified or default background color.
+ ---------------------------------------------------------------------------*/
+
+ if (rpng2_win_create_window()) {
+ readpng2_cleanup(&rpng2_info);
+ return;
+ }
+
+ rpng2_info.state = kWindowInit;
+}
+
+
+
+
+
+static int rpng2_win_create_window()
+{
+ uch bg_red = rpng2_info.bg_red;
+ uch bg_green = rpng2_info.bg_green;
+ uch bg_blue = rpng2_info.bg_blue;
+ uch *dest;
+ int extra_width, extra_height;
+ ulg i, j;
+ WNDCLASSEX wndclass;
+ RECT rect;
+
+
+/*---------------------------------------------------------------------------
+ Allocate memory for the display-specific version of the image (round up
+ to multiple of 4 for Windows DIB).
+ ---------------------------------------------------------------------------*/
+
+ wimage_rowbytes = ((3*rpng2_info.width + 3L) >> 2) << 2;
+
+ if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) +
+ wimage_rowbytes*rpng2_info.height)))
+ {
+ return 4; /* fail */
+ }
+
+/*---------------------------------------------------------------------------
+ Initialize the DIB. Negative height means to use top-down BMP ordering
+ (must be uncompressed, but that's what we want). Bit count of 1, 4 or 8
+ implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values
+ directly => wimage_data begins immediately after BMP header.
+ ---------------------------------------------------------------------------*/
+
+ memset(dib, 0, sizeof(BITMAPINFOHEADER));
+ bmih = (BITMAPINFOHEADER *)dib;
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = rpng2_info.width;
+ bmih->biHeight = -((long)rpng2_info.height);
+ bmih->biPlanes = 1;
+ bmih->biBitCount = 24;
+ bmih->biCompression = 0;
+ wimage_data = dib + sizeof(BITMAPINFOHEADER);
+
+/*---------------------------------------------------------------------------
+ Fill window with the specified background color (default is black), but
+ defer loading faked "background image" until window is displayed (may be
+ slow to compute). Data are in BGR order.
+ ---------------------------------------------------------------------------*/
+
+ if (bg_image) { /* just fill with black for now */
+ memset(wimage_data, 0, wimage_rowbytes*rpng2_info.height);
+ } else {
+ for (j = 0; j < rpng2_info.height; ++j) {
+ dest = wimage_data + j*wimage_rowbytes;
+ for (i = rpng2_info.width; i > 0; --i) {
+ *dest++ = bg_blue;
+ *dest++ = bg_green;
+ *dest++ = bg_red;
+ }
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Set the window parameters.
+ ---------------------------------------------------------------------------*/
+
+ memset(&wndclass, 0, sizeof(wndclass));
+
+ wndclass.cbSize = sizeof(wndclass);
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = rpng2_win_wndproc;
+ wndclass.hInstance = global_hInst;
+ wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = progname;
+ wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+
+ RegisterClassEx(&wndclass);
+
+/*---------------------------------------------------------------------------
+ Finally, create the window.
+ ---------------------------------------------------------------------------*/
+
+ extra_width = 2*(GetSystemMetrics(SM_CXBORDER) +
+ GetSystemMetrics(SM_CXDLGFRAME));
+ extra_height = 2*(GetSystemMetrics(SM_CYBORDER) +
+ GetSystemMetrics(SM_CYDLGFRAME)) +
+ GetSystemMetrics(SM_CYCAPTION);
+
+ global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, rpng2_info.width+extra_width,
+ rpng2_info.height+extra_height, NULL, NULL, global_hInst, NULL);
+
+ ShowWindow(global_hwnd, global_showmode);
+ UpdateWindow(global_hwnd);
+
+/*---------------------------------------------------------------------------
+ Now compute the background image and display it. If it fails (memory
+ allocation), revert to a plain background color.
+ ---------------------------------------------------------------------------*/
+
+ if (bg_image) {
+ static const char *msg = "Computing background image...";
+ int x, y, len = strlen(msg);
+ HDC hdc = GetDC(global_hwnd);
+ TEXTMETRIC tm;
+
+ GetTextMetrics(hdc, &tm);
+ x = (rpng2_info.width - len*tm.tmAveCharWidth)/2;
+ y = (rpng2_info.height - tm.tmHeight)/2;
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ /* this can still begin out of bounds even if x is positive (???): */
+ TextOut(hdc, ((x < 0)? 0 : x), ((y < 0)? 0 : y), msg, len);
+ ReleaseDC(global_hwnd, hdc);
+
+ rpng2_win_load_bg_image(); /* resets bg_image if fails */
+ }
+
+ if (!bg_image) {
+ for (j = 0; j < rpng2_info.height; ++j) {
+ dest = wimage_data + j*wimage_rowbytes;
+ for (i = rpng2_info.width; i > 0; --i) {
+ *dest++ = bg_blue;
+ *dest++ = bg_green;
+ *dest++ = bg_red;
+ }
+ }
+ }
+
+ rect.left = 0L;
+ rect.top = 0L;
+ rect.right = (LONG)rpng2_info.width; /* possibly off by one? */
+ rect.bottom = (LONG)rpng2_info.height; /* possibly off by one? */
+ InvalidateRect(global_hwnd, &rect, FALSE);
+ UpdateWindow(global_hwnd); /* similar to XFlush() */
+
+ return 0;
+
+} /* end function rpng2_win_create_window() */
+
+
+
+
+
+static int rpng2_win_load_bg_image()
+{
+ uch *src, *dest;
+ uch r1, r2, g1, g2, b1, b2;
+ uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
+ int k, hmax, max;
+ int xidx, yidx, yidx_max = (bgscale-1);
+ int even_odd_vert, even_odd_horiz, even_odd;
+ int invert_gradient2 = (bg[pat].type & 0x08);
+ int invert_column;
+ ulg i, row;
+
+/*---------------------------------------------------------------------------
+ Allocate buffer for fake background image to be used with transparent
+ images; if this fails, revert to plain background color.
+ ---------------------------------------------------------------------------*/
+
+ bg_rowbytes = 3 * rpng2_info.width;
+ bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
+ if (!bg_data) {
+ fprintf(stderr, PROGNAME
+ ": unable to allocate memory for background image\n");
+ bg_image = 0;
+ return 1;
+ }
+
+/*---------------------------------------------------------------------------
+ Vertical gradients (ramps) in NxN squares, alternating direction and
+ colors (N == bgscale).
+ ---------------------------------------------------------------------------*/
+
+ if ((bg[pat].type & 0x07) == 0) {
+ uch r1_min = rgb[bg[pat].rgb1_min].r;
+ uch g1_min = rgb[bg[pat].rgb1_min].g;
+ uch b1_min = rgb[bg[pat].rgb1_min].b;
+ uch r2_min = rgb[bg[pat].rgb2_min].r;
+ uch g2_min = rgb[bg[pat].rgb2_min].g;
+ uch b2_min = rgb[bg[pat].rgb2_min].b;
+ int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
+ int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
+ int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
+ int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
+ int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
+ int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ yidx = row % bgscale;
+ even_odd_vert = (row / bgscale) & 1;
+
+ r1 = r1_min + (r1_diff * yidx) / yidx_max;
+ g1 = g1_min + (g1_diff * yidx) / yidx_max;
+ b1 = b1_min + (b1_diff * yidx) / yidx_max;
+ r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
+ g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
+ b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
+
+ r2 = r2_min + (r2_diff * yidx) / yidx_max;
+ g2 = g2_min + (g2_diff * yidx) / yidx_max;
+ b2 = b2_min + (b2_diff * yidx) / yidx_max;
+ r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
+ g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
+ b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
+
+ dest = bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ even_odd_horiz = (i / bgscale) & 1;
+ even_odd = even_odd_vert ^ even_odd_horiz;
+ invert_column =
+ (even_odd_horiz && (bg[pat].type & 0x10));
+ if (even_odd == 0) { /* gradient #1 */
+ if (invert_column) {
+ *dest++ = r1_inv;
+ *dest++ = g1_inv;
+ *dest++ = b1_inv;
+ } else {
+ *dest++ = r1;
+ *dest++ = g1;
+ *dest++ = b1;
+ }
+ } else { /* gradient #2 */
+ if ((invert_column && invert_gradient2) ||
+ (!invert_column && !invert_gradient2))
+ {
+ *dest++ = r2; /* not inverted or */
+ *dest++ = g2; /* doubly inverted */
+ *dest++ = b2;
+ } else {
+ *dest++ = r2_inv;
+ *dest++ = g2_inv; /* singly inverted */
+ *dest++ = b2_inv;
+ }
+ }
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
+ M. Costello.
+ ---------------------------------------------------------------------------*/
+
+ } else if ((bg[pat].type & 0x07) == 1) {
+
+ hmax = (bgscale-1)/2; /* half the max weight of a color */
+ max = 2*hmax; /* the max weight of a color */
+
+ r1 = rgb[bg[pat].rgb1_max].r;
+ g1 = rgb[bg[pat].rgb1_max].g;
+ b1 = rgb[bg[pat].rgb1_max].b;
+ r2 = rgb[bg[pat].rgb2_max].r;
+ g2 = rgb[bg[pat].rgb2_max].g;
+ b2 = rgb[bg[pat].rgb2_max].b;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ yidx = row % bgscale;
+ if (yidx > hmax)
+ yidx = bgscale-1 - yidx;
+ dest = bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ xidx = i % bgscale;
+ if (xidx > hmax)
+ xidx = bgscale-1 - xidx;
+ k = xidx + yidx;
+ *dest++ = (k*r1 + (max-k)*r2) / max;
+ *dest++ = (k*g1 + (max-k)*g2) / max;
+ *dest++ = (k*b1 + (max-k)*b2) / max;
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
+ soids will equal bgscale?]. This one is slow but very cool. Code con-
+ tributed by Pieter S. van der Meulen (originally in Smalltalk).
+ ---------------------------------------------------------------------------*/
+
+ } else if ((bg[pat].type & 0x07) == 2) {
+ uch ch;
+ int ii, x, y, hw, hh, grayspot;
+ double freq, rotate, saturate, gray, intensity;
+ double angle=0.0, aoffset=0.0, maxDist, dist;
+ double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
+
+ fprintf(stderr, "%s: computing radial background...",
+ PROGNAME);
+ fflush(stderr);
+
+ hh = rpng2_info.height / 2;
+ hw = rpng2_info.width / 2;
+
+ /* variables for radial waves:
+ * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
+ * freq: number of color beams originating from the center
+ * grayspot: size of the graying center area (anti-alias)
+ * rotate: rotation of the beams as a function of radius
+ * saturate: saturation of beams' shape azimuthally
+ */
+ angle = CLIP(angle, 0.0, 360.0);
+ grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
+ freq = MAX((double)bg[pat].bg_freq, 0.0);
+ saturate = (double)bg[pat].bg_bsat * 0.1;
+ rotate = (double)bg[pat].bg_brot * 0.1;
+ gray = 0.0;
+ intensity = 0.0;
+ maxDist = (double)((hw*hw) + (hh*hh));
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ y = row - hh;
+ dest = bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ x = i - hw;
+ angle = (x == 0)? PI_2 : atan((double)y / (double)x);
+ gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
+ gray = MIN(1.0, gray);
+ dist = (double)((x*x) + (y*y)) / maxDist;
+ intensity = cos((angle+(rotate*dist*PI)) * freq) *
+ gray * saturate;
+ intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
+ hue = (angle + PI) * INV_PI_360 + aoffset;
+ s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
+ s = MIN(MAX(s,0.0), 1.0);
+ v = MIN(MAX(intensity,0.0), 1.0);
+
+ if (s == 0.0) {
+ ch = (uch)(v * 255.0);
+ *dest++ = ch;
+ *dest++ = ch;
+ *dest++ = ch;
+ } else {
+ if ((hue < 0.0) || (hue >= 360.0))
+ hue -= (((int)(hue / 360.0)) * 360.0);
+ hue /= 60.0;
+ ii = (int)hue;
+ f = hue - (double)ii;
+ p = (1.0 - s) * v;
+ q = (1.0 - (s * f)) * v;
+ t = (1.0 - (s * (1.0 - f))) * v;
+ if (ii == 0) { red = v; green = t; blue = p; }
+ else if (ii == 1) { red = q; green = v; blue = p; }
+ else if (ii == 2) { red = p; green = v; blue = t; }
+ else if (ii == 3) { red = p; green = q; blue = v; }
+ else if (ii == 4) { red = t; green = p; blue = v; }
+ else if (ii == 5) { red = v; green = p; blue = q; }
+ *dest++ = (uch)(red * 255.0);
+ *dest++ = (uch)(green * 255.0);
+ *dest++ = (uch)(blue * 255.0);
+ }
+ }
+ }
+ fprintf(stderr, "done.\n");
+ fflush(stderr);
+ }
+
+/*---------------------------------------------------------------------------
+ Blast background image to display buffer before beginning PNG decode;
+ calling function will handle invalidation and UpdateWindow() call.
+ ---------------------------------------------------------------------------*/
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ src = bg_data + row*bg_rowbytes;
+ dest = wimage_data + row*wimage_rowbytes;
+ for (i = rpng2_info.width; i > 0; --i) {
+ r1 = *src++;
+ g1 = *src++;
+ b1 = *src++;
+ *dest++ = b1;
+ *dest++ = g1; /* note reverse order */
+ *dest++ = r1;
+ }
+ }
+
+ return 0;
+
+} /* end function rpng2_win_load_bg_image() */
+
+
+
+
+
+static void rpng2_win_display_row(ulg row)
+{
+ uch bg_red = rpng2_info.bg_red;
+ uch bg_green = rpng2_info.bg_green;
+ uch bg_blue = rpng2_info.bg_blue;
+ uch *src, *src2=NULL, *dest;
+ uch r, g, b, a;
+ ulg i;
+ static int rows=0;
+ static ulg firstrow;
+
+/*---------------------------------------------------------------------------
+ rows and firstrow simply track how many rows (and which ones) have not
+ yet been displayed; alternatively, we could call InvalidateRect() for
+ every row and not bother with the records-keeping.
+ ---------------------------------------------------------------------------*/
+
+ Trace((stderr, "beginning rpng2_win_display_row()\n"))
+
+ if (rows == 0)
+ firstrow = row; /* first row not yet displayed */
+
+ ++rows; /* count of rows received but not yet displayed */
+
+/*---------------------------------------------------------------------------
+ Aside from the use of the rpng2_info struct and the lack of an outer
+ loop (over rows), this routine is identical to rpng_win_display_image()
+ in the non-progressive version of the program.
+ ---------------------------------------------------------------------------*/
+
+ src = rpng2_info.image_data + row*rpng2_info.rowbytes;
+ if (bg_image)
+ src2 = bg_data + row*bg_rowbytes;
+ dest = wimage_data + row*wimage_rowbytes;
+
+ if (rpng2_info.channels == 3) {
+ for (i = rpng2_info.width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ *dest++ = b;
+ *dest++ = g; /* note reverse order */
+ *dest++ = r;
+ }
+ } else /* if (rpng2_info.channels == 4) */ {
+ for (i = rpng2_info.width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (bg_image) {
+ bg_red = *src2++;
+ bg_green = *src2++;
+ bg_blue = *src2++;
+ }
+ if (a == 255) {
+ *dest++ = b;
+ *dest++ = g;
+ *dest++ = r;
+ } else if (a == 0) {
+ *dest++ = bg_blue;
+ *dest++ = bg_green;
+ *dest++ = bg_red;
+ } else {
+ /* this macro (copied from png.h) composites the
+ * foreground and background values and puts the
+ * result into the first argument; there are no
+ * side effects with the first argument */
+ alpha_composite(*dest++, b, a, bg_blue);
+ alpha_composite(*dest++, g, a, bg_green);
+ alpha_composite(*dest++, r, a, bg_red);
+ }
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Display after every 16 rows or when on last row. (Region may include
+ previously displayed lines due to interlacing--i.e., not contiguous.)
+ ---------------------------------------------------------------------------*/
+
+ if ((rows & 0xf) == 0 || row == rpng2_info.height-1) {
+ RECT rect;
+
+ rect.left = 0L;
+ rect.top = (LONG)firstrow;
+ rect.right = (LONG)rpng2_info.width; /* possibly off by one? */
+ rect.bottom = (LONG)row + 1L; /* possibly off by one? */
+ InvalidateRect(global_hwnd, &rect, FALSE);
+ UpdateWindow(global_hwnd); /* similar to XFlush() */
+ rows = 0;
+ }
+
+} /* end function rpng2_win_display_row() */
+
+
+
+
+
+static void rpng2_win_finish_display()
+{
+ Trace((stderr, "beginning rpng2_win_finish_display()\n"))
+
+ /* last row has already been displayed by rpng2_win_display_row(), so
+ * we have nothing to do here except set a flag and let the user know
+ * that the image is done */
+
+ rpng2_info.state = kDone;
+ printf(
+ "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
+ fflush(stdout);
+}
+
+
+
+
+
+static void rpng2_win_cleanup()
+{
+ if (bg_image && bg_data) {
+ free(bg_data);
+ bg_data = NULL;
+ }
+
+ if (rpng2_info.image_data) {
+ free(rpng2_info.image_data);
+ rpng2_info.image_data = NULL;
+ }
+
+ if (rpng2_info.row_pointers) {
+ free(rpng2_info.row_pointers);
+ rpng2_info.row_pointers = NULL;
+ }
+
+ if (dib) {
+ free(dib);
+ dib = NULL;
+ }
+}
+
+
+
+
+
+LRESULT CALLBACK rpng2_win_wndproc(HWND hwnd, UINT iMsg, WPARAM wP, LPARAM lP)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ int rc;
+
+ switch (iMsg) {
+ case WM_CREATE:
+ /* one-time processing here, if any */
+ return 0;
+
+ case WM_PAINT:
+ hdc = BeginPaint(hwnd, &ps);
+ rc = StretchDIBits(hdc, 0, 0, rpng2_info.width, rpng2_info.height,
+ 0, 0, rpng2_info.width, rpng2_info.height,
+ wimage_data, (BITMAPINFO *)bmih,
+ 0, SRCCOPY);
+ EndPaint(hwnd, &ps);
+ return 0;
+
+ /* wait for the user to tell us when to quit */
+ case WM_CHAR:
+ switch (wP) { /* only need one, so ignore repeat count */
+ case 'q':
+ case 'Q':
+ case 0x1B: /* Esc key */
+ PostQuitMessage(0);
+ }
+ return 0;
+
+ case WM_LBUTTONDOWN: /* another way of quitting */
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, iMsg, wP, lP);
+}
diff --git a/contrib/gregbook/rpng2-x.c b/contrib/gregbook/rpng2-x.c
new file mode 100644
index 0000000..873af23
--- /dev/null
+++ b/contrib/gregbook/rpng2-x.c
@@ -0,0 +1,2127 @@
+/*---------------------------------------------------------------------------
+
+ rpng2 - progressive-model PNG display program rpng2-x.c
+
+ This program decodes and displays PNG files progressively, as if it were
+ a web browser (though the front end is only set up to read from files).
+ It supports gamma correction, user-specified background colors, and user-
+ specified background patterns (for transparent images). This version is
+ for the X Window System (tested by the author under Unix and by Martin
+ Zinser under OpenVMS; may work under OS/2 with a little tweaking).
+
+ Thanks to Adam Costello and Pieter S. van der Meulen for the "diamond"
+ and "radial waves" patterns, respectively.
+
+ to do (someday, maybe):
+ - fix expose/redraw code: don't draw entire row if only part exposed
+ - 8-bit (colormapped) X support
+ - finish resizable checkerboard-gradient (sizes 4-128?)
+ - use %.1023s to simplify truncation of title-bar string?
+
+ ---------------------------------------------------------------------------
+
+ Changelog:
+ - 1.01: initial public release
+ - 1.02: modified to allow abbreviated options; fixed char/uchar mismatch
+ - 1.10: added support for non-default visuals; fixed X pixel-conversion
+ - 1.11: added -usleep option for demos; fixed command-line parsing bug
+ - 1.12: added -pause option for demos and testing
+ - 1.20: added runtime MMX-enabling/disabling and new -mmx* options
+ - 1.21: fixed some small X memory leaks (thanks to François Petitjean)
+ - 1.22: fixed XFreeGC() crash bug (thanks to Patrick Welche)
+ - 1.23: added -bgpat 0 mode (std white/gray checkerboard, 8x8 squares)
+ - 1.30: added -loop option for -bgpat (ifdef FEATURE_LOOP); fixed bpp =
+ 24; added support for X resources (thanks to Gerhard Niklasch)
+ - 1.31: added code to skip unused chunks (thanks to Glenn Randers-Pehrson)
+ - 1.32: added AMD64/EM64T support (__x86_64__); added basic expose/redraw
+ handling
+ - 2.00: dual-licensed (added GNU GPL)
+ - 2.01: fixed 64-bit typo in readpng2.c; fixed -pause usage description
+ - 2.02: fixed improper display of usage screen on PNG error(s); fixed
+ unexpected-EOF and file-read-error cases; fixed Trace() cut-and-
+ paste bugs
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2008 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#define PROGNAME "rpng2-x"
+#define LONGNAME "Progressive PNG Viewer for X"
+#define VERSION "2.02 of 16 March 2008"
+#define RESNAME "rpng2" /* our X resource application name */
+#define RESCLASS "Rpng" /* our X resource class name */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <setjmp.h> /* for jmpbuf declaration in readpng2.h */
+#include <time.h>
+#include <math.h> /* only for PvdM background code */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/keysym.h> /* defines XK_* macros */
+
+#ifdef VMS
+# include <unistd.h>
+#endif
+
+/* all for PvdM background code: */
+#ifndef PI
+# define PI 3.141592653589793238
+#endif
+#define PI_2 (PI*0.5)
+#define INV_PI_360 (360.0 / PI)
+#define MAX(a,b) (a>b?a:b)
+#define MIN(a,b) (a<b?a:b)
+#define CLIP(a,min,max) MAX(min,MIN((a),max))
+#define ABS(a) ((a)<0?-(a):(a))
+#define CLIP8P(c) MAX(0,(MIN((c),255))) /* 8-bit pos. integer (uch) */
+#define ROUNDF(f) ((int)(f + 0.5))
+
+#define QUIT(e,k) ((e.type == ButtonPress && e.xbutton.button == Button1) || \
+ (e.type == KeyPress && /* v--- or 1 for shifted keys */ \
+ ((k = XLookupKeysym(&e.xkey, 0)) == XK_q || k == XK_Escape)))
+
+#define NO_24BIT_MASKS /* undef case not fully written--only for redisplay() */
+
+#define rgb1_max bg_freq
+#define rgb1_min bg_gray
+#define rgb2_max bg_bsat
+#define rgb2_min bg_brot
+
+/* #define DEBUG */ /* this enables the Trace() macros */
+
+#include "readpng2.h" /* typedefs, common macros, readpng2 prototypes */
+
+
+/* could just include png.h, but this macro is the only thing we need
+ * (name and typedefs changed to local versions); note that side effects
+ * only happen with alpha (which could easily be avoided with
+ * "ush acopy = (alpha);") */
+
+#define alpha_composite(composite, fg, alpha, bg) { \
+ ush temp = ((ush)(fg)*(ush)(alpha) + \
+ (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128); \
+ (composite) = (uch)((temp + (temp >> 8)) >> 8); \
+}
+
+
+#define INBUFSIZE 4096 /* with pseudo-timing on (1 sec delay/block), this
+ * block size corresponds roughly to a download
+ * speed 10% faster than theoretical 33.6K maximum
+ * (assuming 8 data bits, 1 stop bit and no other
+ * overhead) */
+
+/* local prototypes */
+static void rpng2_x_init (void);
+static int rpng2_x_create_window (void);
+static int rpng2_x_load_bg_image (void);
+static void rpng2_x_display_row (ulg row);
+static void rpng2_x_finish_display (void);
+static void rpng2_x_redisplay_image (ulg startcol, ulg startrow,
+ ulg width, ulg height);
+#ifdef FEATURE_LOOP
+static void rpng2_x_reload_bg_image (void);
+static int is_number (char *p);
+#endif
+static void rpng2_x_cleanup (void);
+static int rpng2_x_msb (ulg u32val);
+
+
+static char titlebar[1024], *window_name = titlebar;
+static char *appname = LONGNAME;
+static char *icon_name = PROGNAME;
+static char *res_name = RESNAME;
+static char *res_class = RESCLASS;
+static char *filename;
+static FILE *infile;
+
+static mainprog_info rpng2_info;
+
+static uch inbuf[INBUFSIZE];
+static int incount;
+
+static int pat = 6; /* must be less than num_bgpat */
+static int bg_image = 0;
+static int bgscale, bgscale_default = 16;
+static ulg bg_rowbytes;
+static uch *bg_data;
+
+int pause_after_pass = FALSE;
+int demo_timing = FALSE;
+ulg usleep_duration = 0L;
+
+static struct rgb_color {
+ uch r, g, b;
+} rgb[] = {
+ { 0, 0, 0}, /* 0: black */
+ {255, 255, 255}, /* 1: white */
+ {173, 132, 57}, /* 2: tan */
+ { 64, 132, 0}, /* 3: medium green */
+ {189, 117, 1}, /* 4: gold */
+ {253, 249, 1}, /* 5: yellow */
+ { 0, 0, 255}, /* 6: blue */
+ { 0, 0, 120}, /* 7: medium blue */
+ {255, 0, 255}, /* 8: magenta */
+ { 64, 0, 64}, /* 9: dark magenta */
+ {255, 0, 0}, /* 10: red */
+ { 64, 0, 0}, /* 11: dark red */
+ {255, 127, 0}, /* 12: orange */
+ {192, 96, 0}, /* 13: darker orange */
+ { 24, 60, 0}, /* 14: dark green-yellow */
+ { 85, 125, 200}, /* 15: ice blue */
+ {192, 192, 192} /* 16: Netscape/Mosaic gray */
+};
+/* not used for now, but should be for error-checking:
+static int num_rgb = sizeof(rgb) / sizeof(struct rgb_color);
+ */
+
+/*
+ This whole struct is a fairly cheesy way to keep the number of
+ command-line options to a minimum. The radial-waves background
+ type is a particularly poor fit to the integer elements of the
+ struct...but a few macros and a little fixed-point math will do
+ wonders for ya.
+
+ type bits:
+ F E D C B A 9 8 7 6 5 4 3 2 1 0
+ | | | | |
+ | | +-+-+-- 0 = sharp-edged checkerboard
+ | | 1 = soft diamonds
+ | | 2 = radial waves
+ | | 3-7 = undefined
+ | +-- gradient #2 inverted?
+ +-- alternating columns inverted?
+ */
+static struct background_pattern {
+ ush type;
+ int rgb1_max, rgb1_min; /* or bg_freq, bg_gray */
+ int rgb2_max, rgb2_min; /* or bg_bsat, bg_brot (both scaled by 10)*/
+} bg[] = {
+ {0, 1,1, 16,16}, /* checkered: white vs. light gray (basic) */
+ {0+8, 2,0, 1,15}, /* checkered: tan/black vs. white/ice blue */
+ {0+24, 2,0, 1,0}, /* checkered: tan/black vs. white/black */
+ {0+8, 4,5, 0,2}, /* checkered: gold/yellow vs. black/tan */
+ {0+8, 4,5, 0,6}, /* checkered: gold/yellow vs. black/blue */
+ {0, 7,0, 8,9}, /* checkered: deep blue/black vs. magenta */
+ {0+8, 13,0, 5,14}, /* checkered: orange/black vs. yellow */
+ {0+8, 12,0, 10,11}, /* checkered: orange/black vs. red */
+ {1, 7,0, 8,0}, /* diamonds: deep blue/black vs. magenta */
+ {1, 12,0, 11,0}, /* diamonds: orange vs. dark red */
+ {1, 10,0, 7,0}, /* diamonds: red vs. medium blue */
+ {1, 4,0, 5,0}, /* diamonds: gold vs. yellow */
+ {1, 3,0, 0,0}, /* diamonds: medium green vs. black */
+ {2, 16, 100, 20, 0}, /* radial: ~hard radial color-beams */
+ {2, 18, 100, 10, 2}, /* radial: soft, curved radial color-beams */
+ {2, 16, 256, 100, 250}, /* radial: very tight spiral */
+ {2, 10000, 256, 11, 0} /* radial: dipole-moire' (almost fractal) */
+};
+static int num_bgpat = sizeof(bg) / sizeof(struct background_pattern);
+
+
+/* X-specific variables */
+static char *displayname;
+static XImage *ximage;
+static Display *display;
+static int depth;
+static Visual *visual;
+static XVisualInfo *visual_list;
+static int RShift, GShift, BShift;
+static ulg RMask, GMask, BMask;
+static Window window;
+static GC gc;
+static Colormap colormap;
+
+static int have_nondefault_visual = FALSE;
+static int have_colormap = FALSE;
+static int have_window = FALSE;
+static int have_gc = FALSE;
+
+
+
+
+int main(int argc, char **argv)
+{
+#ifdef sgi
+ char tmpline[80];
+#endif
+ char *p, *bgstr = NULL;
+ int rc, alen, flen;
+ int error = 0;
+ int timing = FALSE;
+ int have_bg = FALSE;
+#ifdef FEATURE_LOOP
+ int loop = FALSE;
+ long loop_interval = -1; /* seconds (100,000 max) */
+#endif
+ double LUT_exponent; /* just the lookup table */
+ double CRT_exponent = 2.2; /* just the monitor */
+ double default_display_exponent; /* whole display system */
+ XEvent e;
+ KeySym k;
+
+
+ /* First initialize a few things, just to be sure--memset takes care of
+ * default background color (black), booleans (FALSE), pointers (NULL),
+ * etc. */
+
+ displayname = (char *)NULL;
+ filename = (char *)NULL;
+ memset(&rpng2_info, 0, sizeof(mainprog_info));
+
+
+ /* Set the default value for our display-system exponent, i.e., the
+ * product of the CRT exponent and the exponent corresponding to
+ * the frame-buffer's lookup table (LUT), if any. This is not an
+ * exhaustive list of LUT values (e.g., OpenStep has a lot of weird
+ * ones), but it should cover 99% of the current possibilities. */
+
+#if defined(NeXT)
+ /* third-party utilities can modify the default LUT exponent */
+ LUT_exponent = 1.0 / 2.2;
+ /*
+ if (some_next_function_that_returns_gamma(&next_gamma))
+ LUT_exponent = 1.0 / next_gamma;
+ */
+#elif defined(sgi)
+ LUT_exponent = 1.0 / 1.7;
+ /* there doesn't seem to be any documented function to
+ * get the "gamma" value, so we do it the hard way */
+ infile = fopen("/etc/config/system.glGammaVal", "r");
+ if (infile) {
+ double sgi_gamma;
+
+ fgets(tmpline, 80, infile);
+ fclose(infile);
+ sgi_gamma = atof(tmpline);
+ if (sgi_gamma > 0.0)
+ LUT_exponent = 1.0 / sgi_gamma;
+ }
+#elif defined(Macintosh)
+ LUT_exponent = 1.8 / 2.61;
+ /*
+ if (some_mac_function_that_returns_gamma(&mac_gamma))
+ LUT_exponent = mac_gamma / 2.61;
+ */
+#else
+ LUT_exponent = 1.0; /* assume no LUT: most PCs */
+#endif
+
+ /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
+ default_display_exponent = LUT_exponent * CRT_exponent;
+
+
+ /* If the user has set the SCREEN_GAMMA environment variable as suggested
+ * (somewhat imprecisely) in the libpng documentation, use that; otherwise
+ * use the default value we just calculated. Either way, the user may
+ * override this via a command-line option. */
+
+ if ((p = getenv("SCREEN_GAMMA")) != NULL)
+ rpng2_info.display_exponent = atof(p);
+ else
+ rpng2_info.display_exponent = default_display_exponent;
+
+
+ /* Now parse the command line for options and the PNG filename. */
+
+ while (*++argv && !error) {
+ if (!strncmp(*argv, "-display", 2)) {
+ if (!*++argv)
+ ++error;
+ else
+ displayname = *argv;
+ } else if (!strncmp(*argv, "-gamma", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ rpng2_info.display_exponent = atof(*argv);
+ if (rpng2_info.display_exponent <= 0.0)
+ ++error;
+ }
+ } else if (!strncmp(*argv, "-bgcolor", 4)) {
+ if (!*++argv)
+ ++error;
+ else {
+ bgstr = *argv;
+ if (strlen(bgstr) != 7 || bgstr[0] != '#')
+ ++error;
+ else {
+ have_bg = TRUE;
+ bg_image = FALSE;
+ }
+ }
+ } else if (!strncmp(*argv, "-bgpat", 4)) {
+ if (!*++argv)
+ ++error;
+ else {
+ pat = atoi(*argv);
+ if (pat >= 0 && pat < num_bgpat) {
+ bg_image = TRUE;
+ have_bg = FALSE;
+ } else
+ ++error;
+ }
+ } else if (!strncmp(*argv, "-usleep", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ usleep_duration = (ulg)atol(*argv);
+ demo_timing = TRUE;
+ }
+ } else if (!strncmp(*argv, "-pause", 2)) {
+ pause_after_pass = TRUE;
+ } else if (!strncmp(*argv, "-timing", 2)) {
+ timing = TRUE;
+#ifdef FEATURE_LOOP
+ } else if (!strncmp(*argv, "-loop", 2)) {
+ loop = TRUE;
+ if (!argv[1] || !is_number(argv[1]))
+ loop_interval = 2;
+ else {
+ ++argv;
+ loop_interval = atol(*argv);
+ if (loop_interval < 0)
+ loop_interval = 2;
+ else if (loop_interval > 100000) /* bit more than one day */
+ loop_interval = 100000;
+ }
+#endif
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ } else if (!strncmp(*argv, "-nommxfilters", 7)) {
+ rpng2_info.nommxfilters = TRUE;
+ } else if (!strncmp(*argv, "-nommxcombine", 7)) {
+ rpng2_info.nommxcombine = TRUE;
+ } else if (!strncmp(*argv, "-nommxinterlace", 7)) {
+ rpng2_info.nommxinterlace = TRUE;
+ } else if (!strcmp(*argv, "-nommx")) {
+ rpng2_info.nommxfilters = TRUE;
+ rpng2_info.nommxcombine = TRUE;
+ rpng2_info.nommxinterlace = TRUE;
+#endif
+ } else {
+ if (**argv != '-') {
+ filename = *argv;
+ if (argv[1]) /* shouldn't be any more args after filename */
+ ++error;
+ } else
+ ++error; /* not expecting any other options */
+ }
+ }
+
+ if (!filename)
+ ++error;
+
+
+ /* print usage screen if any errors up to this point */
+
+ if (error) {
+ fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname);
+ readpng2_version_info();
+ fprintf(stderr, "\n"
+ "Usage: %s [-display xdpy] [-gamma exp] [-bgcolor bg | -bgpat pat]\n"
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ " %*s [[-nommxfilters] [-nommxcombine] [-nommxinterlace] | -nommx]\n"
+#endif
+#ifdef FEATURE_LOOP
+ " %*s [-usleep dur | -timing] [-pause] [-loop [sec]] file.png\n\n"
+#else
+ " %*s [-usleep dur | -timing] [-pause] file.png\n\n"
+#endif
+ " xdpy\tname of the target X display (e.g., ``hostname:0'')\n"
+ " exp \ttransfer-function exponent (``gamma'') of the display\n"
+ "\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
+ "\t\t to the product of the lookup-table exponent (varies)\n"
+ "\t\t and the CRT exponent (usually 2.2); must be positive\n"
+ " bg \tdesired background color in 7-character hex RGB format\n"
+ "\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
+ "\t\t used with transparent images; overrides -bgpat\n"
+ " pat \tdesired background pattern number (0-%d); used with\n"
+ "\t\t transparent images; overrides -bgcolor\n"
+#ifdef FEATURE_LOOP
+ " -loop\tloops through background images after initial display\n"
+ "\t\t is complete (depends on -bgpat)\n"
+ " sec \tseconds to display each background image (default = 2)\n"
+#endif
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ " -nommx*\tdisable optimized MMX routines for decoding row filters,\n"
+ "\t\t combining rows, and expanding interlacing, respectively\n"
+#endif
+ " dur \tduration in microseconds to wait after displaying each\n"
+ "\t\t row (for demo purposes)\n"
+ " -timing\tenables delay for every block read, to simulate modem\n"
+ "\t\t download of image (~36 Kbps)\n"
+ " -pause\tpauses after displaying each pass until mouse clicked\n"
+ "\nPress Q, Esc or mouse button 1 (within image window, after image\n"
+ "is displayed) to quit.\n"
+ "\n", PROGNAME,
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__))
+ (int)strlen(PROGNAME), " ",
+#endif
+ (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat-1);
+ exit(1);
+ }
+
+
+ if (!(infile = fopen(filename, "rb"))) {
+ fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
+ ++error;
+ } else {
+ incount = fread(inbuf, 1, INBUFSIZE, infile);
+ if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
+ fprintf(stderr, PROGNAME
+ ": [%s] is not a PNG file: incorrect signature\n",
+ filename);
+ ++error;
+ } else if ((rc = readpng2_init(&rpng2_info)) != 0) {
+ switch (rc) {
+ case 2:
+ fprintf(stderr, PROGNAME
+ ": [%s] has bad IHDR (libpng longjmp)\n", filename);
+ break;
+ case 4:
+ fprintf(stderr, PROGNAME ": insufficient memory\n");
+ break;
+ default:
+ fprintf(stderr, PROGNAME
+ ": unknown readpng2_init() error\n");
+ break;
+ }
+ ++error;
+ } else {
+ Trace((stderr, "about to call XOpenDisplay()\n"))
+ display = XOpenDisplay(displayname);
+ if (!display) {
+ readpng2_cleanup(&rpng2_info);
+ fprintf(stderr, PROGNAME ": can't open X display [%s]\n",
+ displayname? displayname : "default");
+ ++error;
+ }
+ }
+ if (error)
+ fclose(infile);
+ }
+
+
+ if (error) {
+ fprintf(stderr, PROGNAME ": aborting.\n");
+ exit(2);
+ }
+
+
+ /* set the title-bar string, but make sure buffer doesn't overflow */
+
+ alen = strlen(appname);
+ flen = strlen(filename);
+ if (alen + flen + 3 > 1023)
+ sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
+ else
+ sprintf(titlebar, "%s: %s", appname, filename);
+
+
+ /* set some final rpng2_info variables before entering main data loop */
+
+ if (have_bg) {
+ unsigned r, g, b; /* this approach quiets compiler warnings */
+
+ sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
+ rpng2_info.bg_red = (uch)r;
+ rpng2_info.bg_green = (uch)g;
+ rpng2_info.bg_blue = (uch)b;
+ } else
+ rpng2_info.need_bgcolor = TRUE;
+
+ rpng2_info.state = kPreInit;
+ rpng2_info.mainprog_init = rpng2_x_init;
+ rpng2_info.mainprog_display_row = rpng2_x_display_row;
+ rpng2_info.mainprog_finish_display = rpng2_x_finish_display;
+
+
+ /* OK, this is the fun part: call readpng2_decode_data() at the start of
+ * the loop to deal with our first buffer of data (read in above to verify
+ * that the file is a PNG image), then loop through the file and continue
+ * calling the same routine to handle each chunk of data. It in turn
+ * passes the data to libpng, which will invoke one or more of our call-
+ * backs as decoded data become available. We optionally call sleep() for
+ * one second per iteration to simulate downloading the image via an analog
+ * modem. */
+
+ for (;;) {
+ Trace((stderr, "about to call readpng2_decode_data()\n"))
+ if (readpng2_decode_data(&rpng2_info, inbuf, incount))
+ ++error;
+ Trace((stderr, "done with readpng2_decode_data()\n"))
+
+ if (error || incount != INBUFSIZE || rpng2_info.state == kDone) {
+ if (rpng2_info.state == kDone) {
+ Trace((stderr, "done decoding PNG image\n"))
+ } else if (ferror(infile)) {
+ fprintf(stderr, PROGNAME
+ ": error while reading PNG image file\n");
+ exit(3);
+ } else if (feof(infile)) {
+ fprintf(stderr, PROGNAME ": end of file reached "
+ "(unexpectedly) while reading PNG image file\n");
+ exit(3);
+ } else /* if (error) */ {
+ // will print error message below
+ }
+ break;
+ }
+
+ if (timing)
+ sleep(1);
+
+ incount = fread(inbuf, 1, INBUFSIZE, infile);
+ }
+
+
+ /* clean up PNG stuff and report any decoding errors */
+
+ fclose(infile);
+ Trace((stderr, "about to call readpng2_cleanup()\n"))
+ readpng2_cleanup(&rpng2_info);
+
+ if (error) {
+ fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n");
+ exit(3);
+ }
+
+
+#ifdef FEATURE_LOOP
+
+ if (loop && bg_image) {
+ Trace((stderr, "entering -loop loop (FEATURE_LOOP)\n"))
+ for (;;) {
+ int i, use_sleep;
+ struct timeval now, then;
+
+ /* get current time and add loop_interval to get target time */
+ if (gettimeofday(&then, NULL) == 0) {
+ then.tv_sec += loop_interval;
+ use_sleep = FALSE;
+ } else
+ use_sleep = TRUE;
+
+ /* do quick check for a quit event but don't wait for it */
+ /* GRR BUG: should also check for Expose events and redraw... */
+ if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, &e))
+ if (QUIT(e,k))
+ break;
+
+ /* generate next background image */
+ if (++pat >= num_bgpat)
+ pat = 0;
+ rpng2_x_reload_bg_image();
+
+ /* wait for timeout, using whatever means are available */
+ if (use_sleep || gettimeofday(&now, NULL) != 0) {
+ for (i = loop_interval; i > 0; --i) {
+ sleep(1);
+ /* GRR BUG: also need to check for Expose (and redraw!) */
+ if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask,
+ &e) && QUIT(e,k))
+ break;
+ }
+ } else {
+ /* Y2038 BUG! */
+ if (now.tv_sec < then.tv_sec ||
+ (now.tv_sec == then.tv_sec && now.tv_usec < then.tv_usec))
+ {
+ int quit = FALSE;
+ long seconds_to_go = then.tv_sec - now.tv_sec;
+ long usleep_usec;
+
+ /* basically chew up most of remaining loop-interval with
+ * calls to sleep(1) interleaved with checks for quit
+ * events, but also recalc time-to-go periodically; when
+ * done, clean up any remaining time with usleep() call
+ * (could also use SIGALRM, but signals are a pain...) */
+ while (seconds_to_go-- > 1) {
+ int seconds_done = 0;
+
+ for (i = seconds_to_go; i > 0 && !quit; --i) {
+ sleep(1);
+ /* GRR BUG: need to check for Expose and redraw */
+ if (XCheckMaskEvent(display, KeyPressMask |
+ ButtonPressMask, &e) && QUIT(e,k))
+ quit = TRUE;
+ if (++seconds_done > 1000)
+ break; /* time to redo seconds_to_go meas. */
+ }
+ if (quit)
+ break;
+
+ /* OK, more than 1000 seconds since last check:
+ * correct the time-to-go measurement for drift */
+ if (gettimeofday(&now, NULL) == 0) {
+ if (now.tv_sec >= then.tv_sec)
+ break;
+ seconds_to_go = then.tv_sec - now.tv_sec;
+ } else
+ ++seconds_to_go; /* restore what we subtracted */
+ }
+ if (quit)
+ break; /* breaks outer do-loop, skips redisplay */
+
+ /* since difference between "now" and "then" is already
+ * eaten up to within a couple of seconds, don't need to
+ * worry about overflow--but might have overshot (neg.) */
+ if (gettimeofday(&now, NULL) == 0) {
+ usleep_usec = 1000000L*(then.tv_sec - now.tv_sec) +
+ then.tv_usec - now.tv_usec;
+ if (usleep_usec > 0)
+ usleep((ulg)usleep_usec);
+ }
+ }
+ }
+
+ /* composite image against new background and display (note that
+ * we do not take into account the time spent doing this...) */
+ rpng2_x_redisplay_image (0, 0, rpng2_info.width, rpng2_info.height);
+ }
+
+ } else /* FALL THROUGH and do the normal thing */
+
+#endif /* FEATURE_LOOP */
+
+ /* wait for the user to tell us when to quit */
+
+ if (rpng2_info.state >= kWindowInit) {
+ Trace((stderr, "entering final wait-for-quit-event loop\n"))
+ do {
+ XNextEvent(display, &e);
+ if (e.type == Expose) {
+ XExposeEvent *ex = (XExposeEvent *)&e;
+ rpng2_x_redisplay_image (ex->x, ex->y, ex->width, ex->height);
+ }
+ } while (!QUIT(e,k));
+ } else {
+ fprintf(stderr, PROGNAME ": init callback never called: probable "
+ "libpng error while decoding PNG metadata\n");
+ exit(4);
+ }
+
+
+ /* we're done: clean up all image and X resources and go away */
+
+ Trace((stderr, "about to call rpng2_x_cleanup()\n"))
+ rpng2_x_cleanup();
+
+ return 0;
+}
+
+
+
+
+
+/* this function is called by readpng2_info_callback() in readpng2.c, which
+ * in turn is called by libpng after all of the pre-IDAT chunks have been
+ * read and processed--i.e., we now have enough info to finish initializing */
+
+static void rpng2_x_init(void)
+{
+ ulg i;
+ ulg rowbytes = rpng2_info.rowbytes;
+
+ Trace((stderr, "beginning rpng2_x_init()\n"))
+ Trace((stderr, " rowbytes = %d\n", rpng2_info.rowbytes))
+ Trace((stderr, " width = %ld\n", rpng2_info.width))
+ Trace((stderr, " height = %ld\n", rpng2_info.height))
+
+ rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
+ if (!rpng2_info.image_data) {
+ readpng2_cleanup(&rpng2_info);
+ return;
+ }
+
+ rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
+ if (!rpng2_info.row_pointers) {
+ free(rpng2_info.image_data);
+ rpng2_info.image_data = NULL;
+ readpng2_cleanup(&rpng2_info);
+ return;
+ }
+
+ for (i = 0; i < rpng2_info.height; ++i)
+ rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
+
+
+ /* do the basic X initialization stuff, make the window, and fill it with
+ * the user-specified, file-specified or default background color or
+ * pattern */
+
+ if (rpng2_x_create_window()) {
+
+ /* GRR TEMPORARY HACK: this is fundamentally no different from cases
+ * above; libpng should longjmp() back to us when png_ptr goes away.
+ * If we/it segfault instead, seems like a libpng bug... */
+
+ /* we're here via libpng callback, so if window fails, clean and bail */
+ readpng2_cleanup(&rpng2_info);
+ rpng2_x_cleanup();
+ exit(2);
+ }
+
+ rpng2_info.state = kWindowInit;
+}
+
+
+
+
+
+static int rpng2_x_create_window(void)
+{
+ ulg bg_red = rpng2_info.bg_red;
+ ulg bg_green = rpng2_info.bg_green;
+ ulg bg_blue = rpng2_info.bg_blue;
+ ulg bg_pixel = 0L;
+ ulg attrmask;
+ int need_colormap = FALSE;
+ int screen, pad;
+ uch *xdata;
+ Window root;
+ XEvent e;
+ XGCValues gcvalues;
+ XSetWindowAttributes attr;
+ XTextProperty windowName, *pWindowName = &windowName;
+ XTextProperty iconName, *pIconName = &iconName;
+ XVisualInfo visual_info;
+ XSizeHints *size_hints;
+ XWMHints *wm_hints;
+ XClassHint *class_hints;
+
+
+ Trace((stderr, "beginning rpng2_x_create_window()\n"))
+
+ screen = DefaultScreen(display);
+ depth = DisplayPlanes(display, screen);
+ root = RootWindow(display, screen);
+
+#ifdef DEBUG
+ XSynchronize(display, True);
+#endif
+
+ if (depth != 16 && depth != 24 && depth != 32) {
+ int visuals_matched = 0;
+
+ Trace((stderr, "default depth is %d: checking other visuals\n",
+ depth))
+
+ /* 24-bit first */
+ visual_info.screen = screen;
+ visual_info.depth = 24;
+ visual_list = XGetVisualInfo(display,
+ VisualScreenMask | VisualDepthMask, &visual_info, &visuals_matched);
+ if (visuals_matched == 0) {
+/* GRR: add 15-, 16- and 32-bit TrueColor visuals (also DirectColor?) */
+ fprintf(stderr, "default screen depth %d not supported, and no"
+ " 24-bit visuals found\n", depth);
+ return 2;
+ }
+ Trace((stderr, "XGetVisualInfo() returned %d 24-bit visuals\n",
+ visuals_matched))
+ visual = visual_list[0].visual;
+ depth = visual_list[0].depth;
+/*
+ colormap_size = visual_list[0].colormap_size;
+ visual_class = visual->class;
+ visualID = XVisualIDFromVisual(visual);
+ */
+ have_nondefault_visual = TRUE;
+ need_colormap = TRUE;
+ } else {
+ XMatchVisualInfo(display, screen, depth, TrueColor, &visual_info);
+ visual = visual_info.visual;
+ }
+
+ RMask = visual->red_mask;
+ GMask = visual->green_mask;
+ BMask = visual->blue_mask;
+
+/* GRR: add/check 8-bit support */
+ if (depth == 8 || need_colormap) {
+ colormap = XCreateColormap(display, root, visual, AllocNone);
+ if (!colormap) {
+ fprintf(stderr, "XCreateColormap() failed\n");
+ return 2;
+ }
+ have_colormap = TRUE;
+ if (depth == 8)
+ bg_image = FALSE; /* gradient just wastes palette entries */
+ }
+ if (depth == 15 || depth == 16) {
+ RShift = 15 - rpng2_x_msb(RMask); /* these are right-shifts */
+ GShift = 15 - rpng2_x_msb(GMask);
+ BShift = 15 - rpng2_x_msb(BMask);
+ } else if (depth > 16) {
+ RShift = rpng2_x_msb(RMask) - 7; /* these are left-shifts */
+ GShift = rpng2_x_msb(GMask) - 7;
+ BShift = rpng2_x_msb(BMask) - 7;
+ }
+ if (depth >= 15 && (RShift < 0 || GShift < 0 || BShift < 0)) {
+ fprintf(stderr, "rpng2 internal logic error: negative X shift(s)!\n");
+ return 2;
+ }
+
+/*---------------------------------------------------------------------------
+ Finally, create the window.
+ ---------------------------------------------------------------------------*/
+
+ attr.backing_store = Always;
+ attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
+ attrmask = CWBackingStore | CWEventMask;
+ if (have_nondefault_visual) {
+ attr.colormap = colormap;
+ attr.background_pixel = 0;
+ attr.border_pixel = 1;
+ attrmask |= CWColormap | CWBackPixel | CWBorderPixel;
+ }
+
+ window = XCreateWindow(display, root, 0, 0, rpng2_info.width,
+ rpng2_info.height, 0, depth, InputOutput, visual, attrmask, &attr);
+
+ if (window == None) {
+ fprintf(stderr, "XCreateWindow() failed\n");
+ return 2;
+ } else
+ have_window = TRUE;
+
+ if (depth == 8)
+ XSetWindowColormap(display, window, colormap);
+
+ if (!XStringListToTextProperty(&window_name, 1, pWindowName))
+ pWindowName = NULL;
+ if (!XStringListToTextProperty(&icon_name, 1, pIconName))
+ pIconName = NULL;
+
+ /* OK if either hints allocation fails; XSetWMProperties() allows NULLs */
+
+ if ((size_hints = XAllocSizeHints()) != NULL) {
+ /* window will not be resizable */
+ size_hints->flags = PMinSize | PMaxSize;
+ size_hints->min_width = size_hints->max_width = (int)rpng2_info.width;
+ size_hints->min_height = size_hints->max_height =
+ (int)rpng2_info.height;
+ }
+
+ if ((wm_hints = XAllocWMHints()) != NULL) {
+ wm_hints->initial_state = NormalState;
+ wm_hints->input = True;
+ /* wm_hints->icon_pixmap = icon_pixmap; */
+ wm_hints->flags = StateHint | InputHint /* | IconPixmapHint */ ;
+ }
+
+ if ((class_hints = XAllocClassHint()) != NULL) {
+ class_hints->res_name = res_name;
+ class_hints->res_class = res_class;
+ }
+
+ XSetWMProperties(display, window, pWindowName, pIconName, NULL, 0,
+ size_hints, wm_hints, class_hints);
+
+ /* various properties and hints no longer needed; free memory */
+ if (pWindowName)
+ XFree(pWindowName->value);
+ if (pIconName)
+ XFree(pIconName->value);
+ if (size_hints)
+ XFree(size_hints);
+ if (wm_hints)
+ XFree(wm_hints);
+ if (class_hints)
+ XFree(class_hints);
+
+ XMapWindow(display, window);
+
+ gc = XCreateGC(display, window, 0, &gcvalues);
+ have_gc = TRUE;
+
+/*---------------------------------------------------------------------------
+ Allocate memory for the X- and display-specific version of the image.
+ ---------------------------------------------------------------------------*/
+
+ if (depth == 24 || depth == 32) {
+ xdata = (uch *)malloc(4*rpng2_info.width*rpng2_info.height);
+ pad = 32;
+ } else if (depth == 16) {
+ xdata = (uch *)malloc(2*rpng2_info.width*rpng2_info.height);
+ pad = 16;
+ } else /* depth == 8 */ {
+ xdata = (uch *)malloc(rpng2_info.width*rpng2_info.height);
+ pad = 8;
+ }
+
+ if (!xdata) {
+ fprintf(stderr, PROGNAME ": unable to allocate image memory\n");
+ return 4;
+ }
+
+ ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
+ (char *)xdata, rpng2_info.width, rpng2_info.height, pad, 0);
+
+ if (!ximage) {
+ fprintf(stderr, PROGNAME ": XCreateImage() failed\n");
+ free(xdata);
+ return 3;
+ }
+
+ /* to avoid testing the byte order every pixel (or doubling the size of
+ * the drawing routine with a giant if-test), we arbitrarily set the byte
+ * order to MSBFirst and let Xlib worry about inverting things on little-
+ * endian machines (e.g., Linux/x86, old VAXen, etc.)--this is not the
+ * most efficient approach (the giant if-test would be better), but in
+ * the interest of clarity, we'll take the easy way out... */
+
+ ximage->byte_order = MSBFirst;
+
+/*---------------------------------------------------------------------------
+ Fill window with the specified background color (default is black) or
+ faked "background image" (but latter is disabled if 8-bit; gradients
+ just waste palette entries).
+ ---------------------------------------------------------------------------*/
+
+ if (bg_image)
+ rpng2_x_load_bg_image(); /* resets bg_image if fails */
+
+ if (!bg_image) {
+ if (depth == 24 || depth == 32) {
+ bg_pixel = (bg_red << RShift) |
+ (bg_green << GShift) |
+ (bg_blue << BShift);
+ } else if (depth == 16) {
+ bg_pixel = (((bg_red << 8) >> RShift) & RMask) |
+ (((bg_green << 8) >> GShift) & GMask) |
+ (((bg_blue << 8) >> BShift) & BMask);
+ } else /* depth == 8 */ {
+
+ /* GRR: add 8-bit support */
+
+ }
+ XSetForeground(display, gc, bg_pixel);
+ XFillRectangle(display, window, gc, 0, 0, rpng2_info.width,
+ rpng2_info.height);
+ }
+
+/*---------------------------------------------------------------------------
+ Wait for first Expose event to do any drawing, then flush and return.
+ ---------------------------------------------------------------------------*/
+
+ do
+ XNextEvent(display, &e);
+ while (e.type != Expose || e.xexpose.count);
+
+ XFlush(display);
+
+ return 0;
+
+} /* end function rpng2_x_create_window() */
+
+
+
+
+
+static int rpng2_x_load_bg_image(void)
+{
+ uch *src;
+ char *dest;
+ uch r1, r2, g1, g2, b1, b2;
+ uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
+ int k, hmax, max;
+ int xidx, yidx, yidx_max;
+ int even_odd_vert, even_odd_horiz, even_odd;
+ int invert_gradient2 = (bg[pat].type & 0x08);
+ int invert_column;
+ int ximage_rowbytes = ximage->bytes_per_line;
+ ulg i, row;
+ ulg pixel;
+
+/*---------------------------------------------------------------------------
+ Allocate buffer for fake background image to be used with transparent
+ images; if this fails, revert to plain background color.
+ ---------------------------------------------------------------------------*/
+
+ bg_rowbytes = 3 * rpng2_info.width;
+ bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
+ if (!bg_data) {
+ fprintf(stderr, PROGNAME
+ ": unable to allocate memory for background image\n");
+ bg_image = 0;
+ return 1;
+ }
+
+ bgscale = (pat == 0)? 8 : bgscale_default;
+ yidx_max = bgscale - 1;
+
+/*---------------------------------------------------------------------------
+ Vertical gradients (ramps) in NxN squares, alternating direction and
+ colors (N == bgscale).
+ ---------------------------------------------------------------------------*/
+
+ if ((bg[pat].type & 0x07) == 0) {
+ uch r1_min = rgb[bg[pat].rgb1_min].r;
+ uch g1_min = rgb[bg[pat].rgb1_min].g;
+ uch b1_min = rgb[bg[pat].rgb1_min].b;
+ uch r2_min = rgb[bg[pat].rgb2_min].r;
+ uch g2_min = rgb[bg[pat].rgb2_min].g;
+ uch b2_min = rgb[bg[pat].rgb2_min].b;
+ int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
+ int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
+ int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
+ int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
+ int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
+ int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ yidx = (int)(row % bgscale);
+ even_odd_vert = (int)((row / bgscale) & 1);
+
+ r1 = r1_min + (r1_diff * yidx) / yidx_max;
+ g1 = g1_min + (g1_diff * yidx) / yidx_max;
+ b1 = b1_min + (b1_diff * yidx) / yidx_max;
+ r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
+ g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
+ b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
+
+ r2 = r2_min + (r2_diff * yidx) / yidx_max;
+ g2 = g2_min + (g2_diff * yidx) / yidx_max;
+ b2 = b2_min + (b2_diff * yidx) / yidx_max;
+ r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
+ g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
+ b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
+
+ dest = (char *)bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ even_odd_horiz = (int)((i / bgscale) & 1);
+ even_odd = even_odd_vert ^ even_odd_horiz;
+ invert_column =
+ (even_odd_horiz && (bg[pat].type & 0x10));
+ if (even_odd == 0) { /* gradient #1 */
+ if (invert_column) {
+ *dest++ = r1_inv;
+ *dest++ = g1_inv;
+ *dest++ = b1_inv;
+ } else {
+ *dest++ = r1;
+ *dest++ = g1;
+ *dest++ = b1;
+ }
+ } else { /* gradient #2 */
+ if ((invert_column && invert_gradient2) ||
+ (!invert_column && !invert_gradient2))
+ {
+ *dest++ = r2; /* not inverted or */
+ *dest++ = g2; /* doubly inverted */
+ *dest++ = b2;
+ } else {
+ *dest++ = r2_inv;
+ *dest++ = g2_inv; /* singly inverted */
+ *dest++ = b2_inv;
+ }
+ }
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
+ M. Costello.
+ ---------------------------------------------------------------------------*/
+
+ } else if ((bg[pat].type & 0x07) == 1) {
+
+ hmax = (bgscale-1)/2; /* half the max weight of a color */
+ max = 2*hmax; /* the max weight of a color */
+
+ r1 = rgb[bg[pat].rgb1_max].r;
+ g1 = rgb[bg[pat].rgb1_max].g;
+ b1 = rgb[bg[pat].rgb1_max].b;
+ r2 = rgb[bg[pat].rgb2_max].r;
+ g2 = rgb[bg[pat].rgb2_max].g;
+ b2 = rgb[bg[pat].rgb2_max].b;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ yidx = (int)(row % bgscale);
+ if (yidx > hmax)
+ yidx = bgscale-1 - yidx;
+ dest = (char *)bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ xidx = (int)(i % bgscale);
+ if (xidx > hmax)
+ xidx = bgscale-1 - xidx;
+ k = xidx + yidx;
+ *dest++ = (k*r1 + (max-k)*r2) / max;
+ *dest++ = (k*g1 + (max-k)*g2) / max;
+ *dest++ = (k*b1 + (max-k)*b2) / max;
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
+ soids will equal bgscale?]. This one is slow but very cool. Code con-
+ tributed by Pieter S. van der Meulen (originally in Smalltalk).
+ ---------------------------------------------------------------------------*/
+
+ } else if ((bg[pat].type & 0x07) == 2) {
+ uch ch;
+ int ii, x, y, hw, hh, grayspot;
+ double freq, rotate, saturate, gray, intensity;
+ double angle=0.0, aoffset=0.0, maxDist, dist;
+ double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
+
+ fprintf(stderr, "%s: computing radial background...",
+ PROGNAME);
+ fflush(stderr);
+
+ hh = (int)(rpng2_info.height / 2);
+ hw = (int)(rpng2_info.width / 2);
+
+ /* variables for radial waves:
+ * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
+ * freq: number of color beams originating from the center
+ * grayspot: size of the graying center area (anti-alias)
+ * rotate: rotation of the beams as a function of radius
+ * saturate: saturation of beams' shape azimuthally
+ */
+ angle = CLIP(angle, 0.0, 360.0);
+ grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
+ freq = MAX((double)bg[pat].bg_freq, 0.0);
+ saturate = (double)bg[pat].bg_bsat * 0.1;
+ rotate = (double)bg[pat].bg_brot * 0.1;
+ gray = 0.0;
+ intensity = 0.0;
+ maxDist = (double)((hw*hw) + (hh*hh));
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ y = (int)(row - hh);
+ dest = (char *)bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ x = (int)(i - hw);
+ angle = (x == 0)? PI_2 : atan((double)y / (double)x);
+ gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
+ gray = MIN(1.0, gray);
+ dist = (double)((x*x) + (y*y)) / maxDist;
+ intensity = cos((angle+(rotate*dist*PI)) * freq) *
+ gray * saturate;
+ intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
+ hue = (angle + PI) * INV_PI_360 + aoffset;
+ s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
+ s = MIN(MAX(s,0.0), 1.0);
+ v = MIN(MAX(intensity,0.0), 1.0);
+
+ if (s == 0.0) {
+ ch = (uch)(v * 255.0);
+ *dest++ = ch;
+ *dest++ = ch;
+ *dest++ = ch;
+ } else {
+ if ((hue < 0.0) || (hue >= 360.0))
+ hue -= (((int)(hue / 360.0)) * 360.0);
+ hue /= 60.0;
+ ii = (int)hue;
+ f = hue - (double)ii;
+ p = (1.0 - s) * v;
+ q = (1.0 - (s * f)) * v;
+ t = (1.0 - (s * (1.0 - f))) * v;
+ if (ii == 0) { red = v; green = t; blue = p; }
+ else if (ii == 1) { red = q; green = v; blue = p; }
+ else if (ii == 2) { red = p; green = v; blue = t; }
+ else if (ii == 3) { red = p; green = q; blue = v; }
+ else if (ii == 4) { red = t; green = p; blue = v; }
+ else if (ii == 5) { red = v; green = p; blue = q; }
+ *dest++ = (uch)(red * 255.0);
+ *dest++ = (uch)(green * 255.0);
+ *dest++ = (uch)(blue * 255.0);
+ }
+ }
+ }
+ fprintf(stderr, "done.\n");
+ fflush(stderr);
+ }
+
+/*---------------------------------------------------------------------------
+ Blast background image to display buffer before beginning PNG decode.
+ ---------------------------------------------------------------------------*/
+
+ if (depth == 24 || depth == 32) {
+ ulg red, green, blue;
+ int bpp = ximage->bits_per_pixel;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ src = bg_data + row*bg_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ if (bpp == 32) { /* slightly optimized version */
+ for (i = rpng2_info.width; i > 0; --i) {
+ red = *src++;
+ green = *src++;
+ blue = *src++;
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ } else {
+ for (i = rpng2_info.width; i > 0; --i) {
+ red = *src++;
+ green = *src++;
+ blue = *src++;
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ /* GRR BUG? this assumes bpp == 24 & bits are packed low */
+ /* (probably need to use RShift, RMask, etc.) */
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+ }
+
+ } else if (depth == 16) {
+ ush red, green, blue;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ src = bg_data + row*bg_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ for (i = rpng2_info.width; i > 0; --i) {
+ red = ((ush)(*src) << 8); ++src;
+ green = ((ush)(*src) << 8); ++src;
+ blue = ((ush)(*src) << 8); ++src;
+ pixel = ((red >> RShift) & RMask) |
+ ((green >> GShift) & GMask) |
+ ((blue >> BShift) & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+
+ } else /* depth == 8 */ {
+
+ /* GRR: add 8-bit support */
+
+ }
+
+ XPutImage(display, window, gc, ximage, 0, 0, 0, 0, rpng2_info.width,
+ rpng2_info.height);
+
+ return 0;
+
+} /* end function rpng2_x_load_bg_image() */
+
+
+
+
+
+static void rpng2_x_display_row(ulg row)
+{
+ uch bg_red = rpng2_info.bg_red;
+ uch bg_green = rpng2_info.bg_green;
+ uch bg_blue = rpng2_info.bg_blue;
+ uch *src, *src2=NULL;
+ char *dest;
+ uch r, g, b, a;
+ int ximage_rowbytes = ximage->bytes_per_line;
+ ulg i, pixel;
+ static int rows=0, prevpass=(-1);
+ static ulg firstrow;
+
+/*---------------------------------------------------------------------------
+ rows and firstrow simply track how many rows (and which ones) have not
+ yet been displayed; alternatively, we could call XPutImage() for every
+ row and not bother with the records-keeping.
+ ---------------------------------------------------------------------------*/
+
+ Trace((stderr, "beginning rpng2_x_display_row()\n"))
+
+ if (rpng2_info.pass != prevpass) {
+ if (pause_after_pass && rpng2_info.pass > 0) {
+ XEvent e;
+ KeySym k;
+
+ fprintf(stderr,
+ "%s: end of pass %d of 7; click in image window to continue\n",
+ PROGNAME, prevpass + 1);
+ do
+ XNextEvent(display, &e);
+ while (!QUIT(e,k));
+ }
+ fprintf(stderr, "%s: pass %d of 7\r", PROGNAME, rpng2_info.pass + 1);
+ fflush(stderr);
+ prevpass = rpng2_info.pass;
+ }
+
+ if (rows == 0)
+ firstrow = row; /* first row that is not yet displayed */
+
+ ++rows; /* count of rows received but not yet displayed */
+
+/*---------------------------------------------------------------------------
+ Aside from the use of the rpng2_info struct, the lack of an outer loop
+ (over rows) and moving the XPutImage() call outside the "if (depth)"
+ tests, this routine is identical to rpng_x_display_image() in the non-
+ progressive version of the program.
+ ---------------------------------------------------------------------------*/
+
+ if (depth == 24 || depth == 32) {
+ ulg red, green, blue;
+ int bpp = ximage->bits_per_pixel;
+
+ src = rpng2_info.image_data + row*rpng2_info.rowbytes;
+ if (bg_image)
+ src2 = bg_data + row*bg_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ if (rpng2_info.channels == 3) {
+ for (i = rpng2_info.width; i > 0; --i) {
+ red = *src++;
+ green = *src++;
+ blue = *src++;
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ if (bpp == 32) {
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ } else {
+ /* GRR BUG? this assumes bpp == 24 & bits are packed low */
+ /* (probably need to use RShift, RMask, etc.) */
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+ } else /* if (rpng2_info.channels == 4) */ {
+ for (i = rpng2_info.width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (bg_image) {
+ bg_red = *src2++;
+ bg_green = *src2++;
+ bg_blue = *src2++;
+ }
+ if (a == 255) {
+ red = r;
+ green = g;
+ blue = b;
+ } else if (a == 0) {
+ red = bg_red;
+ green = bg_green;
+ blue = bg_blue;
+ } else {
+ /* this macro (from png.h) composites the foreground
+ * and background values and puts the result into the
+ * first argument */
+ alpha_composite(red, r, a, bg_red);
+ alpha_composite(green, g, a, bg_green);
+ alpha_composite(blue, b, a, bg_blue);
+ }
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ if (bpp == 32) {
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ } else {
+ /* GRR BUG? this assumes bpp == 24 & bits are packed low */
+ /* (probably need to use RShift, RMask, etc.) */
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+ }
+
+ } else if (depth == 16) {
+ ush red, green, blue;
+
+ src = rpng2_info.row_pointers[row];
+ if (bg_image)
+ src2 = bg_data + row*bg_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ if (rpng2_info.channels == 3) {
+ for (i = rpng2_info.width; i > 0; --i) {
+ red = ((ush)(*src) << 8);
+ ++src;
+ green = ((ush)(*src) << 8);
+ ++src;
+ blue = ((ush)(*src) << 8);
+ ++src;
+ pixel = ((red >> RShift) & RMask) |
+ ((green >> GShift) & GMask) |
+ ((blue >> BShift) & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ } else /* if (rpng2_info.channels == 4) */ {
+ for (i = rpng2_info.width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (bg_image) {
+ bg_red = *src2++;
+ bg_green = *src2++;
+ bg_blue = *src2++;
+ }
+ if (a == 255) {
+ red = ((ush)r << 8);
+ green = ((ush)g << 8);
+ blue = ((ush)b << 8);
+ } else if (a == 0) {
+ red = ((ush)bg_red << 8);
+ green = ((ush)bg_green << 8);
+ blue = ((ush)bg_blue << 8);
+ } else {
+ /* this macro (from png.h) composites the foreground
+ * and background values and puts the result back into
+ * the first argument (== fg byte here: safe) */
+ alpha_composite(r, r, a, bg_red);
+ alpha_composite(g, g, a, bg_green);
+ alpha_composite(b, b, a, bg_blue);
+ red = ((ush)r << 8);
+ green = ((ush)g << 8);
+ blue = ((ush)b << 8);
+ }
+ pixel = ((red >> RShift) & RMask) |
+ ((green >> GShift) & GMask) |
+ ((blue >> BShift) & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+
+ } else /* depth == 8 */ {
+
+ /* GRR: add 8-bit support */
+
+ }
+
+
+/*---------------------------------------------------------------------------
+ Display after every 16 rows or when on one of last two rows. (Region
+ may include previously displayed lines due to interlacing--i.e., not
+ contiguous. Also, second-to-last row is final one in interlaced images
+ with odd number of rows.) For demos, flush (and delay) after every 16th
+ row so "sparse" passes don't go twice as fast.
+ ---------------------------------------------------------------------------*/
+
+ if (demo_timing && (row - firstrow >= 16 || row >= rpng2_info.height-2)) {
+ XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
+ (int)firstrow, rpng2_info.width, row - firstrow + 1);
+ XFlush(display);
+ rows = 0;
+ usleep(usleep_duration);
+ } else
+ if (!demo_timing && ((rows & 0xf) == 0 || row >= rpng2_info.height-2)) {
+ XPutImage(display, window, gc, ximage, 0, (int)firstrow, 0,
+ (int)firstrow, rpng2_info.width, row - firstrow + 1);
+ XFlush(display);
+ rows = 0;
+ }
+
+}
+
+
+
+
+
+static void rpng2_x_finish_display(void)
+{
+ Trace((stderr, "beginning rpng2_x_finish_display()\n"))
+
+ /* last row has already been displayed by rpng2_x_display_row(), so we
+ * have nothing to do here except set a flag and let the user know that
+ * the image is done */
+
+ rpng2_info.state = kDone;
+ printf(
+ "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n");
+ fflush(stdout);
+}
+
+
+
+
+
+static void rpng2_x_redisplay_image(ulg startcol, ulg startrow,
+ ulg width, ulg height)
+{
+ uch bg_red = rpng2_info.bg_red;
+ uch bg_green = rpng2_info.bg_green;
+ uch bg_blue = rpng2_info.bg_blue;
+ uch *src, *src2=NULL;
+ char *dest;
+ uch r, g, b, a;
+ ulg i, row, lastrow = 0;
+ ulg pixel;
+ int ximage_rowbytes = ximage->bytes_per_line;
+
+
+ Trace((stderr, "beginning display loop (image_channels == %d)\n",
+ rpng2_info.channels))
+ Trace((stderr, " (width = %ld, rowbytes = %d, ximage_rowbytes = %d)\n",
+ rpng2_info.width, rpng2_info.rowbytes, ximage_rowbytes))
+ Trace((stderr, " (bpp = %d)\n", ximage->bits_per_pixel))
+ Trace((stderr, " (byte_order = %s)\n", ximage->byte_order == MSBFirst?
+ "MSBFirst" : (ximage->byte_order == LSBFirst? "LSBFirst" : "unknown")))
+
+/*---------------------------------------------------------------------------
+ Aside from the use of the rpng2_info struct and of src2 (for background
+ image), this routine is identical to rpng_x_display_image() in the non-
+ progressive version of the program--for the simple reason that redisplay
+ of the image against a new background happens after the image is fully
+ decoded and therefore is, by definition, non-progressive.
+ ---------------------------------------------------------------------------*/
+
+ if (depth == 24 || depth == 32) {
+ ulg red, green, blue;
+ int bpp = ximage->bits_per_pixel;
+
+ for (lastrow = row = startrow; row < startrow+height; ++row) {
+ src = rpng2_info.image_data + row*rpng2_info.rowbytes;
+ if (bg_image)
+ src2 = bg_data + row*bg_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ if (rpng2_info.channels == 3) {
+ for (i = rpng2_info.width; i > 0; --i) {
+ red = *src++;
+ green = *src++;
+ blue = *src++;
+#ifdef NO_24BIT_MASKS
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ if (bpp == 32) {
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ } else {
+ /* this assumes bpp == 24 & bits are packed low */
+ /* (probably need to use RShift, RMask, etc.) */
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+#else
+ red = (RShift < 0)? red << (-RShift) : red >> RShift;
+ green = (GShift < 0)? green << (-GShift) : green >> GShift;
+ blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
+ pixel = (red & RMask) | (green & GMask) | (blue & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ if (bpp == 32) {
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ } else {
+ /* GRR BUG */
+ /* this assumes bpp == 24 & bits are packed low */
+ /* (probably need to use RShift/RMask/etc. here, too) */
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+#endif
+ }
+
+ } else /* if (rpng2_info.channels == 4) */ {
+ for (i = rpng2_info.width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (bg_image) {
+ bg_red = *src2++;
+ bg_green = *src2++;
+ bg_blue = *src2++;
+ }
+ if (a == 255) {
+ red = r;
+ green = g;
+ blue = b;
+ } else if (a == 0) {
+ red = bg_red;
+ green = bg_green;
+ blue = bg_blue;
+ } else {
+ /* this macro (from png.h) composites the foreground
+ * and background values and puts the result into the
+ * first argument */
+ alpha_composite(red, r, a, bg_red);
+ alpha_composite(green, g, a, bg_green);
+ alpha_composite(blue, b, a, bg_blue);
+ }
+#ifdef NO_24BIT_MASKS
+ pixel = (red << RShift) |
+ (green << GShift) |
+ (blue << BShift);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ if (bpp == 32) {
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ } else {
+ /* this assumes bpp == 24 & bits are packed low */
+ /* (probably need to use RShift, RMask, etc.) */
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+#else
+ red = (RShift < 0)? red << (-RShift) : red >> RShift;
+ green = (GShift < 0)? green << (-GShift) : green >> GShift;
+ blue = (BShift < 0)? blue << (-BShift) : blue >> BShift;
+ pixel = (red & RMask) | (green & GMask) | (blue & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ if (bpp == 32) {
+ *dest++ = (char)((pixel >> 24) & 0xff);
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ } else {
+ /* GRR BUG */
+ /* this assumes bpp == 24 & bits are packed low */
+ /* (probably need to use RShift/RMask/etc. here, too) */
+ *dest++ = (char)((pixel >> 16) & 0xff);
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+#endif
+ }
+ }
+ /* display after every 16 lines */
+ if (((row+1) & 0xf) == 0) {
+ XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
+ (int)lastrow, rpng2_info.width, 16);
+ XFlush(display);
+ lastrow = row + 1;
+ }
+ }
+
+ } else if (depth == 16) {
+ ush red, green, blue;
+
+ for (lastrow = row = startrow; row < startrow+height; ++row) {
+ src = rpng2_info.row_pointers[row];
+ if (bg_image)
+ src2 = bg_data + row*bg_rowbytes;
+ dest = ximage->data + row*ximage_rowbytes;
+ if (rpng2_info.channels == 3) {
+ for (i = rpng2_info.width; i > 0; --i) {
+ red = ((ush)(*src) << 8);
+ ++src;
+ green = ((ush)(*src) << 8);
+ ++src;
+ blue = ((ush)(*src) << 8);
+ ++src;
+ pixel = ((red >> RShift) & RMask) |
+ ((green >> GShift) & GMask) |
+ ((blue >> BShift) & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ } else /* if (rpng2_info.channels == 4) */ {
+ for (i = rpng2_info.width; i > 0; --i) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+ if (bg_image) {
+ bg_red = *src2++;
+ bg_green = *src2++;
+ bg_blue = *src2++;
+ }
+ if (a == 255) {
+ red = ((ush)r << 8);
+ green = ((ush)g << 8);
+ blue = ((ush)b << 8);
+ } else if (a == 0) {
+ red = ((ush)bg_red << 8);
+ green = ((ush)bg_green << 8);
+ blue = ((ush)bg_blue << 8);
+ } else {
+ /* this macro (from png.h) composites the foreground
+ * and background values and puts the result back into
+ * the first argument (== fg byte here: safe) */
+ alpha_composite(r, r, a, bg_red);
+ alpha_composite(g, g, a, bg_green);
+ alpha_composite(b, b, a, bg_blue);
+ red = ((ush)r << 8);
+ green = ((ush)g << 8);
+ blue = ((ush)b << 8);
+ }
+ pixel = ((red >> RShift) & RMask) |
+ ((green >> GShift) & GMask) |
+ ((blue >> BShift) & BMask);
+ /* recall that we set ximage->byte_order = MSBFirst above */
+ *dest++ = (char)((pixel >> 8) & 0xff);
+ *dest++ = (char)( pixel & 0xff);
+ }
+ }
+ /* display after every 16 lines */
+ if (((row+1) & 0xf) == 0) {
+ XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
+ (int)lastrow, rpng2_info.width, 16);
+ XFlush(display);
+ lastrow = row + 1;
+ }
+ }
+
+ } else /* depth == 8 */ {
+
+ /* GRR: add 8-bit support */
+
+ }
+
+ Trace((stderr, "calling final XPutImage()\n"))
+ if (lastrow < startrow+height) {
+ XPutImage(display, window, gc, ximage, 0, (int)lastrow, 0,
+ (int)lastrow, rpng2_info.width, rpng2_info.height-lastrow);
+ XFlush(display);
+ }
+
+} /* end function rpng2_x_redisplay_image() */
+
+
+
+
+
+#ifdef FEATURE_LOOP
+
+static void rpng2_x_reload_bg_image(void)
+{
+ char *dest;
+ uch r1, r2, g1, g2, b1, b2;
+ uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
+ int k, hmax, max;
+ int xidx, yidx, yidx_max;
+ int even_odd_vert, even_odd_horiz, even_odd;
+ int invert_gradient2 = (bg[pat].type & 0x08);
+ int invert_column;
+ ulg i, row;
+
+
+ bgscale = (pat == 0)? 8 : bgscale_default;
+ yidx_max = bgscale - 1;
+
+/*---------------------------------------------------------------------------
+ Vertical gradients (ramps) in NxN squares, alternating direction and
+ colors (N == bgscale).
+ ---------------------------------------------------------------------------*/
+
+ if ((bg[pat].type & 0x07) == 0) {
+ uch r1_min = rgb[bg[pat].rgb1_min].r;
+ uch g1_min = rgb[bg[pat].rgb1_min].g;
+ uch b1_min = rgb[bg[pat].rgb1_min].b;
+ uch r2_min = rgb[bg[pat].rgb2_min].r;
+ uch g2_min = rgb[bg[pat].rgb2_min].g;
+ uch b2_min = rgb[bg[pat].rgb2_min].b;
+ int r1_diff = rgb[bg[pat].rgb1_max].r - r1_min;
+ int g1_diff = rgb[bg[pat].rgb1_max].g - g1_min;
+ int b1_diff = rgb[bg[pat].rgb1_max].b - b1_min;
+ int r2_diff = rgb[bg[pat].rgb2_max].r - r2_min;
+ int g2_diff = rgb[bg[pat].rgb2_max].g - g2_min;
+ int b2_diff = rgb[bg[pat].rgb2_max].b - b2_min;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ yidx = (int)(row % bgscale);
+ even_odd_vert = (int)((row / bgscale) & 1);
+
+ r1 = r1_min + (r1_diff * yidx) / yidx_max;
+ g1 = g1_min + (g1_diff * yidx) / yidx_max;
+ b1 = b1_min + (b1_diff * yidx) / yidx_max;
+ r1_inv = r1_min + (r1_diff * (yidx_max-yidx)) / yidx_max;
+ g1_inv = g1_min + (g1_diff * (yidx_max-yidx)) / yidx_max;
+ b1_inv = b1_min + (b1_diff * (yidx_max-yidx)) / yidx_max;
+
+ r2 = r2_min + (r2_diff * yidx) / yidx_max;
+ g2 = g2_min + (g2_diff * yidx) / yidx_max;
+ b2 = b2_min + (b2_diff * yidx) / yidx_max;
+ r2_inv = r2_min + (r2_diff * (yidx_max-yidx)) / yidx_max;
+ g2_inv = g2_min + (g2_diff * (yidx_max-yidx)) / yidx_max;
+ b2_inv = b2_min + (b2_diff * (yidx_max-yidx)) / yidx_max;
+
+ dest = (char *)bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ even_odd_horiz = (int)((i / bgscale) & 1);
+ even_odd = even_odd_vert ^ even_odd_horiz;
+ invert_column =
+ (even_odd_horiz && (bg[pat].type & 0x10));
+ if (even_odd == 0) { /* gradient #1 */
+ if (invert_column) {
+ *dest++ = r1_inv;
+ *dest++ = g1_inv;
+ *dest++ = b1_inv;
+ } else {
+ *dest++ = r1;
+ *dest++ = g1;
+ *dest++ = b1;
+ }
+ } else { /* gradient #2 */
+ if ((invert_column && invert_gradient2) ||
+ (!invert_column && !invert_gradient2))
+ {
+ *dest++ = r2; /* not inverted or */
+ *dest++ = g2; /* doubly inverted */
+ *dest++ = b2;
+ } else {
+ *dest++ = r2_inv;
+ *dest++ = g2_inv; /* singly inverted */
+ *dest++ = b2_inv;
+ }
+ }
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Soft gradient-diamonds with scale = bgscale. Code contributed by Adam
+ M. Costello.
+ ---------------------------------------------------------------------------*/
+
+ } else if ((bg[pat].type & 0x07) == 1) {
+
+ hmax = (bgscale-1)/2; /* half the max weight of a color */
+ max = 2*hmax; /* the max weight of a color */
+
+ r1 = rgb[bg[pat].rgb1_max].r;
+ g1 = rgb[bg[pat].rgb1_max].g;
+ b1 = rgb[bg[pat].rgb1_max].b;
+ r2 = rgb[bg[pat].rgb2_max].r;
+ g2 = rgb[bg[pat].rgb2_max].g;
+ b2 = rgb[bg[pat].rgb2_max].b;
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ yidx = (int)(row % bgscale);
+ if (yidx > hmax)
+ yidx = bgscale-1 - yidx;
+ dest = (char *)bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ xidx = (int)(i % bgscale);
+ if (xidx > hmax)
+ xidx = bgscale-1 - xidx;
+ k = xidx + yidx;
+ *dest++ = (k*r1 + (max-k)*r2) / max;
+ *dest++ = (k*g1 + (max-k)*g2) / max;
+ *dest++ = (k*b1 + (max-k)*b2) / max;
+ }
+ }
+
+/*---------------------------------------------------------------------------
+ Radial "starburst" with azimuthal sinusoids; [eventually number of sinu-
+ soids will equal bgscale?]. This one is slow but very cool. Code con-
+ tributed by Pieter S. van der Meulen (originally in Smalltalk).
+ ---------------------------------------------------------------------------*/
+
+ } else if ((bg[pat].type & 0x07) == 2) {
+ uch ch;
+ int ii, x, y, hw, hh, grayspot;
+ double freq, rotate, saturate, gray, intensity;
+ double angle=0.0, aoffset=0.0, maxDist, dist;
+ double red=0.0, green=0.0, blue=0.0, hue, s, v, f, p, q, t;
+
+ hh = (int)(rpng2_info.height / 2);
+ hw = (int)(rpng2_info.width / 2);
+
+ /* variables for radial waves:
+ * aoffset: number of degrees to rotate hue [CURRENTLY NOT USED]
+ * freq: number of color beams originating from the center
+ * grayspot: size of the graying center area (anti-alias)
+ * rotate: rotation of the beams as a function of radius
+ * saturate: saturation of beams' shape azimuthally
+ */
+ angle = CLIP(angle, 0.0, 360.0);
+ grayspot = CLIP(bg[pat].bg_gray, 1, (hh + hw));
+ freq = MAX((double)bg[pat].bg_freq, 0.0);
+ saturate = (double)bg[pat].bg_bsat * 0.1;
+ rotate = (double)bg[pat].bg_brot * 0.1;
+ gray = 0.0;
+ intensity = 0.0;
+ maxDist = (double)((hw*hw) + (hh*hh));
+
+ for (row = 0; row < rpng2_info.height; ++row) {
+ y = (int)(row - hh);
+ dest = (char *)bg_data + row*bg_rowbytes;
+ for (i = 0; i < rpng2_info.width; ++i) {
+ x = (int)(i - hw);
+ angle = (x == 0)? PI_2 : atan((double)y / (double)x);
+ gray = (double)MAX(ABS(y), ABS(x)) / grayspot;
+ gray = MIN(1.0, gray);
+ dist = (double)((x*x) + (y*y)) / maxDist;
+ intensity = cos((angle+(rotate*dist*PI)) * freq) *
+ gray * saturate;
+ intensity = (MAX(MIN(intensity,1.0),-1.0) + 1.0) * 0.5;
+ hue = (angle + PI) * INV_PI_360 + aoffset;
+ s = gray * ((double)(ABS(x)+ABS(y)) / (double)(hw + hh));
+ s = MIN(MAX(s,0.0), 1.0);
+ v = MIN(MAX(intensity,0.0), 1.0);
+
+ if (s == 0.0) {
+ ch = (uch)(v * 255.0);
+ *dest++ = ch;
+ *dest++ = ch;
+ *dest++ = ch;
+ } else {
+ if ((hue < 0.0) || (hue >= 360.0))
+ hue -= (((int)(hue / 360.0)) * 360.0);
+ hue /= 60.0;
+ ii = (int)hue;
+ f = hue - (double)ii;
+ p = (1.0 - s) * v;
+ q = (1.0 - (s * f)) * v;
+ t = (1.0 - (s * (1.0 - f))) * v;
+ if (ii == 0) { red = v; green = t; blue = p; }
+ else if (ii == 1) { red = q; green = v; blue = p; }
+ else if (ii == 2) { red = p; green = v; blue = t; }
+ else if (ii == 3) { red = p; green = q; blue = v; }
+ else if (ii == 4) { red = t; green = p; blue = v; }
+ else if (ii == 5) { red = v; green = p; blue = q; }
+ *dest++ = (uch)(red * 255.0);
+ *dest++ = (uch)(green * 255.0);
+ *dest++ = (uch)(blue * 255.0);
+ }
+ }
+ }
+ }
+
+} /* end function rpng2_x_reload_bg_image() */
+
+
+
+
+
+static int is_number(char *p)
+{
+ while (*p) {
+ if (!isdigit(*p))
+ return FALSE;
+ ++p;
+ }
+ return TRUE;
+}
+
+#endif /* FEATURE_LOOP */
+
+
+
+
+
+static void rpng2_x_cleanup(void)
+{
+ if (bg_image && bg_data) {
+ free(bg_data);
+ bg_data = NULL;
+ }
+
+ if (rpng2_info.image_data) {
+ free(rpng2_info.image_data);
+ rpng2_info.image_data = NULL;
+ }
+
+ if (rpng2_info.row_pointers) {
+ free(rpng2_info.row_pointers);
+ rpng2_info.row_pointers = NULL;
+ }
+
+ if (ximage) {
+ if (ximage->data) {
+ free(ximage->data); /* we allocated it, so we free it */
+ ximage->data = (char *)NULL; /* instead of XDestroyImage() */
+ }
+ XDestroyImage(ximage);
+ ximage = NULL;
+ }
+
+ if (have_gc)
+ XFreeGC(display, gc);
+
+ if (have_window)
+ XDestroyWindow(display, window);
+
+ if (have_colormap)
+ XFreeColormap(display, colormap);
+
+ if (have_nondefault_visual)
+ XFree(visual_list);
+}
+
+
+
+
+
+static int rpng2_x_msb(ulg u32val)
+{
+ int i;
+
+ for (i = 31; i >= 0; --i) {
+ if (u32val & 0x80000000L)
+ break;
+ u32val <<= 1;
+ }
+ return i;
+}
diff --git a/contrib/gregbook/toucan.png b/contrib/gregbook/toucan.png
new file mode 100644
index 0000000..03960d4
--- /dev/null
+++ b/contrib/gregbook/toucan.png
Binary files differ
diff --git a/contrib/gregbook/wpng.c b/contrib/gregbook/wpng.c
new file mode 100644
index 0000000..a06e352
--- /dev/null
+++ b/contrib/gregbook/wpng.c
@@ -0,0 +1,853 @@
+/*---------------------------------------------------------------------------
+
+ wpng - simple PNG-writing program wpng.c
+
+ This program converts certain NetPBM binary files (grayscale and RGB,
+ maxval = 255) to PNG. Non-interlaced PNGs are written progressively;
+ interlaced PNGs are read and written in one memory-intensive blast.
+
+ Thanks to Jean-loup Gailly for providing the necessary trick to read
+ interactive text from the keyboard while stdin is redirected. Thanks
+ to Cosmin Truta for Cygwin fixes.
+
+ NOTE: includes provisional support for PNM type "8" (portable alphamap)
+ images, presumed to be a 32-bit interleaved RGBA format; no pro-
+ vision for possible interleaved grayscale+alpha (16-bit) format.
+ THIS IS UNLIKELY TO BECOME AN OFFICIAL NETPBM ALPHA FORMAT!
+
+ to do:
+ - delete output file if quit before calling any writepng routines
+ - process backspace with -text option under DOS/Win? (currently get ^H)
+
+ ---------------------------------------------------------------------------
+
+ Changelog:
+ - 1.01: initial public release
+ - 1.02: modified to allow abbreviated options
+ - 1.03: removed extraneous character from usage screen; fixed bug in
+ command-line parsing
+ - 1.04: fixed DOS/OS2/Win32 detection, including partial Cygwin fix
+ (see http://home.att.net/~perlspinr/diffs/GregBook_cygwin.diff)
+ - 2.00: dual-licensed (added GNU GPL)
+
+ [REPORTED BUG (win32 only): "contrib/gregbook/wpng.c - cmd line
+ dose not work! In order to do something useful I needed to redirect
+ both input and output, with cygwin and with bcc32 as well. Under
+ Linux, the same wpng appears to work fine. I don't know what is
+ the problem."]
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#define PROGNAME "wpng"
+#define VERSION "2.00 of 2 June 2007"
+#define APPNAME "Simple PGM/PPM/PAM to PNG Converter"
+
+#if defined(__MSDOS__) || defined(__OS2__)
+# define DOS_OS2_W32
+#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+# ifndef __GNUC__ /* treat Win32 native ports of gcc as Unix environments */
+# define DOS_OS2_W32
+# endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h> /* for jmpbuf declaration in writepng.h */
+#include <time.h>
+
+#ifdef DOS_OS2_W32
+# include <io.h> /* for isatty(), setmode() prototypes */
+# include <fcntl.h> /* O_BINARY for fdopen() without text translation */
+# ifdef __EMX__
+# ifndef getch
+# define getch() _read_kbd(0, 1, 0) /* need getche() */
+# endif
+# else /* !__EMX__ */
+# ifdef __GO32__
+# include <pc.h>
+# define getch() getkey() /* GRR: need getche() */
+# else
+# include <conio.h> /* for getche() console input */
+# endif
+# endif /* ?__EMX__ */
+# define FGETS(buf,len,stream) dos_kbd_gets(buf,len)
+#else
+# include <unistd.h> /* for isatty() prototype */
+# define FGETS fgets
+#endif
+
+/* #define DEBUG : this enables the Trace() macros */
+
+/* #define FORBID_LATIN1_CTRL : this requires the user to re-enter any
+ text that includes control characters discouraged by the PNG spec; text
+ that includes an escape character (27) must be re-entered regardless */
+
+#include "writepng.h" /* typedefs, common macros, writepng prototypes */
+
+
+
+/* local prototypes */
+
+static int wpng_isvalid_latin1(uch *p, int len);
+static void wpng_cleanup(void);
+
+#ifdef DOS_OS2_W32
+ static char *dos_kbd_gets(char *buf, int len);
+#endif
+
+
+
+static mainprog_info wpng_info; /* lone global */
+
+
+
+int main(int argc, char **argv)
+{
+#ifndef DOS_OS2_W32
+ FILE *keybd;
+#endif
+#ifdef sgi
+ FILE *tmpfile; /* or we could just use keybd, since no overlap */
+ char tmpline[80];
+#endif
+ char *inname = NULL, outname[256];
+ char *p, pnmchar, pnmline[256];
+ char *bgstr, *textbuf = NULL;
+ ulg rowbytes;
+ int rc, len = 0;
+ int error = 0;
+ int text = FALSE;
+ int maxval;
+ double LUT_exponent; /* just the lookup table */
+ double CRT_exponent = 2.2; /* just the monitor */
+ double default_display_exponent; /* whole display system */
+ double default_gamma = 0.0;
+
+
+ wpng_info.infile = NULL;
+ wpng_info.outfile = NULL;
+ wpng_info.image_data = NULL;
+ wpng_info.row_pointers = NULL;
+ wpng_info.filter = FALSE;
+ wpng_info.interlaced = FALSE;
+ wpng_info.have_bg = FALSE;
+ wpng_info.have_time = FALSE;
+ wpng_info.have_text = 0;
+ wpng_info.gamma = 0.0;
+
+
+ /* First get the default value for our display-system exponent, i.e.,
+ * the product of the CRT exponent and the exponent corresponding to
+ * the frame-buffer's lookup table (LUT), if any. If the PNM image
+ * looks correct on the user's display system, its file gamma is the
+ * inverse of this value. (Note that this is not an exhaustive list
+ * of LUT values--e.g., OpenStep has a lot of weird ones--but it should
+ * cover 99% of the current possibilities. This section must ensure
+ * that default_display_exponent is positive.) */
+
+#if defined(NeXT)
+ /* third-party utilities can modify the default LUT exponent */
+ LUT_exponent = 1.0 / 2.2;
+ /*
+ if (some_next_function_that_returns_gamma(&next_gamma))
+ LUT_exponent = 1.0 / next_gamma;
+ */
+#elif defined(sgi)
+ LUT_exponent = 1.0 / 1.7;
+ /* there doesn't seem to be any documented function to
+ * get the "gamma" value, so we do it the hard way */
+ tmpfile = fopen("/etc/config/system.glGammaVal", "r");
+ if (tmpfile) {
+ double sgi_gamma;
+
+ fgets(tmpline, 80, tmpfile);
+ fclose(tmpfile);
+ sgi_gamma = atof(tmpline);
+ if (sgi_gamma > 0.0)
+ LUT_exponent = 1.0 / sgi_gamma;
+ }
+#elif defined(Macintosh)
+ LUT_exponent = 1.8 / 2.61;
+ /*
+ if (some_mac_function_that_returns_gamma(&mac_gamma))
+ LUT_exponent = mac_gamma / 2.61;
+ */
+#else
+ LUT_exponent = 1.0; /* assume no LUT: most PCs */
+#endif
+
+ /* the defaults above give 1.0, 1.3, 1.5 and 2.2, respectively: */
+ default_display_exponent = LUT_exponent * CRT_exponent;
+
+
+ /* If the user has set the SCREEN_GAMMA environment variable as suggested
+ * (somewhat imprecisely) in the libpng documentation, use that; otherwise
+ * use the default value we just calculated. Either way, the user may
+ * override this via a command-line option. */
+
+ if ((p = getenv("SCREEN_GAMMA")) != NULL) {
+ double exponent = atof(p);
+
+ if (exponent > 0.0)
+ default_gamma = 1.0 / exponent;
+ }
+
+ if (default_gamma == 0.0)
+ default_gamma = 1.0 / default_display_exponent;
+
+
+ /* Now parse the command line for options and the PNM filename. */
+
+ while (*++argv && !error) {
+ if (!strncmp(*argv, "-i", 2)) {
+ wpng_info.interlaced = TRUE;
+ } else if (!strncmp(*argv, "-time", 3)) {
+ wpng_info.modtime = time(NULL);
+ wpng_info.have_time = TRUE;
+ } else if (!strncmp(*argv, "-text", 3)) {
+ text = TRUE;
+ } else if (!strncmp(*argv, "-gamma", 2)) {
+ if (!*++argv)
+ ++error;
+ else {
+ wpng_info.gamma = atof(*argv);
+ if (wpng_info.gamma <= 0.0)
+ ++error;
+ else if (wpng_info.gamma > 1.01)
+ fprintf(stderr, PROGNAME
+ " warning: file gammas are usually less than 1.0\n");
+ }
+ } else if (!strncmp(*argv, "-bgcolor", 4)) {
+ if (!*++argv)
+ ++error;
+ else {
+ bgstr = *argv;
+ if (strlen(bgstr) != 7 || bgstr[0] != '#')
+ ++error;
+ else {
+ unsigned r, g, b; /* this way quiets compiler warnings */
+
+ sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
+ wpng_info.bg_red = (uch)r;
+ wpng_info.bg_green = (uch)g;
+ wpng_info.bg_blue = (uch)b;
+ wpng_info.have_bg = TRUE;
+ }
+ }
+ } else {
+ if (**argv != '-') {
+ inname = *argv;
+ if (argv[1]) /* shouldn't be any more args after filename */
+ ++error;
+ } else
+ ++error; /* not expecting any other options */
+ }
+ }
+
+
+ /* open the input and output files, or register an error and abort */
+
+ if (!inname) {
+ if (isatty(0)) {
+ fprintf(stderr, PROGNAME
+ ": must give input filename or provide image data via stdin\n");
+ ++error;
+ } else {
+#ifdef DOS_OS2_W32
+ /* some buggy C libraries require BOTH setmode() and fdopen(bin) */
+ setmode(fileno(stdin), O_BINARY);
+ setmode(fileno(stdout), O_BINARY);
+#endif
+ if ((wpng_info.infile = fdopen(fileno(stdin), "rb")) == NULL) {
+ fprintf(stderr, PROGNAME
+ ": unable to reopen stdin in binary mode\n");
+ ++error;
+ } else
+ if ((wpng_info.outfile = fdopen(fileno(stdout), "wb")) == NULL) {
+ fprintf(stderr, PROGNAME
+ ": unable to reopen stdout in binary mode\n");
+ fclose(wpng_info.infile);
+ ++error;
+ } else
+ wpng_info.filter = TRUE;
+ }
+ } else if ((len = strlen(inname)) > 250) {
+ fprintf(stderr, PROGNAME ": input filename is too long [%d chars]\n",
+ len);
+ ++error;
+ } else if (!(wpng_info.infile = fopen(inname, "rb"))) {
+ fprintf(stderr, PROGNAME ": can't open input file [%s]\n", inname);
+ ++error;
+ }
+
+ if (!error) {
+ fgets(pnmline, 256, wpng_info.infile);
+ if (pnmline[0] != 'P' || ((pnmchar = pnmline[1]) != '5' &&
+ pnmchar != '6' && pnmchar != '8'))
+ {
+ fprintf(stderr, PROGNAME
+ ": input file [%s] is not a binary PGM, PPM or PAM file\n",
+ inname);
+ ++error;
+ } else {
+ wpng_info.pnmtype = (int)(pnmchar - '0');
+ if (wpng_info.pnmtype != 8)
+ wpng_info.have_bg = FALSE; /* no need for bg if opaque */
+ do {
+ fgets(pnmline, 256, wpng_info.infile); /* lose any comments */
+ } while (pnmline[0] == '#');
+ sscanf(pnmline, "%ld %ld", &wpng_info.width, &wpng_info.height);
+ do {
+ fgets(pnmline, 256, wpng_info.infile); /* more comment lines */
+ } while (pnmline[0] == '#');
+ sscanf(pnmline, "%d", &maxval);
+ if (wpng_info.width <= 0L || wpng_info.height <= 0L ||
+ maxval != 255)
+ {
+ fprintf(stderr, PROGNAME
+ ": only positive width/height, maxval == 255 allowed \n");
+ ++error;
+ }
+ wpng_info.sample_depth = 8; /* <==> maxval 255 */
+
+ if (!wpng_info.filter) {
+ /* make outname from inname */
+ if ((p = strrchr(inname, '.')) == NULL ||
+ (p - inname) != (len - 4))
+ {
+ strcpy(outname, inname);
+ strcpy(outname+len, ".png");
+ } else {
+ len -= 4;
+ strncpy(outname, inname, len);
+ strcpy(outname+len, ".png");
+ }
+ /* check if outname already exists; if not, open */
+ if ((wpng_info.outfile = fopen(outname, "rb")) != NULL) {
+ fprintf(stderr, PROGNAME ": output file exists [%s]\n",
+ outname);
+ fclose(wpng_info.outfile);
+ ++error;
+ } else if (!(wpng_info.outfile = fopen(outname, "wb"))) {
+ fprintf(stderr, PROGNAME ": can't open output file [%s]\n",
+ outname);
+ ++error;
+ }
+ }
+ }
+ if (error) {
+ fclose(wpng_info.infile);
+ wpng_info.infile = NULL;
+ if (wpng_info.filter) {
+ fclose(wpng_info.outfile);
+ wpng_info.outfile = NULL;
+ }
+ }
+ }
+
+
+ /* if we had any errors, print usage and die horrible death...arrr! */
+
+ if (error) {
+ fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, APPNAME);
+ writepng_version_info();
+ fprintf(stderr, "\n"
+"Usage: %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] pnmfile\n"
+"or: ... | %s [-gamma exp] [-bgcolor bg] [-text] [-time] [-interlace] | ...\n"
+ " exp \ttransfer-function exponent (``gamma'') of the image in\n"
+ "\t\t floating-point format (e.g., ``%.5f''); if image looks\n"
+ "\t\t correct on given display system, image gamma is equal to\n"
+ "\t\t inverse of display-system exponent, i.e., 1 / (LUT * CRT)\n"
+ "\t\t (where LUT = lookup-table exponent and CRT = CRT exponent;\n"
+ "\t\t first varies, second is usually 2.2, all are positive)\n"
+ " bg \tdesired background color for alpha-channel images, in\n"
+ "\t\t 7-character hex RGB format (e.g., ``#ff7700'' for orange:\n"
+ "\t\t same as HTML colors)\n"
+ " -text\tprompt interactively for text info (tEXt chunks)\n"
+ " -time\tinclude a tIME chunk (last modification time)\n"
+ " -interlace\twrite interlaced PNG image\n"
+ "\n"
+"pnmfile or stdin must be a binary PGM (`P5'), PPM (`P6') or (extremely\n"
+"unofficial and unsupported!) PAM (`P8') file. Currently it is required\n"
+"to have maxval == 255 (i.e., no scaling). If pnmfile is specified, it\n"
+"is converted to the corresponding PNG file with the same base name but a\n"
+"``.png'' extension; files read from stdin are converted and sent to stdout.\n"
+"The conversion is progressive (low memory usage) unless interlacing is\n"
+"requested; in that case the whole image will be buffered in memory and\n"
+"written in one call.\n"
+ "\n", PROGNAME, PROGNAME, default_gamma);
+ exit(1);
+ }
+
+
+ /* prepare the text buffers for libpng's use; note that even though
+ * PNG's png_text struct includes a length field, we don't have to fill
+ * it out */
+
+ if (text &&
+#ifndef DOS_OS2_W32
+ (keybd = fdopen(fileno(stderr), "r")) != NULL &&
+#endif
+ (textbuf = (char *)malloc((5 + 9)*75)) != NULL)
+ {
+ int i, valid, result;
+
+ fprintf(stderr,
+ "Enter text info (no more than 72 characters per line);\n");
+ fprintf(stderr, "to skip a field, hit the <Enter> key.\n");
+ /* note: just <Enter> leaves len == 1 */
+
+ do {
+ valid = TRUE;
+ p = textbuf + TEXT_TITLE_OFFSET;
+ fprintf(stderr, " Title: ");
+ fflush(stderr);
+ if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) {
+ if (p[len-1] == '\n')
+ p[--len] = '\0';
+ wpng_info.title = p;
+ wpng_info.have_text |= TEXT_TITLE;
+ if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) {
+ fprintf(stderr, " " PROGNAME " warning: character code"
+ " %u is %sdiscouraged by the PNG\n specification "
+ "[first occurrence was at character position #%d]\n",
+ (unsigned)p[result], (p[result] == 27)? "strongly " : "",
+ result+1);
+ fflush(stderr);
+#ifdef FORBID_LATIN1_CTRL
+ wpng_info.have_text &= ~TEXT_TITLE;
+ valid = FALSE;
+#else
+ if (p[result] == 27) { /* escape character */
+ wpng_info.have_text &= ~TEXT_TITLE;
+ valid = FALSE;
+ }
+#endif
+ }
+ }
+ } while (!valid);
+
+ do {
+ valid = TRUE;
+ p = textbuf + TEXT_AUTHOR_OFFSET;
+ fprintf(stderr, " Author: ");
+ fflush(stderr);
+ if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) {
+ if (p[len-1] == '\n')
+ p[--len] = '\0';
+ wpng_info.author = p;
+ wpng_info.have_text |= TEXT_AUTHOR;
+ if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) {
+ fprintf(stderr, " " PROGNAME " warning: character code"
+ " %u is %sdiscouraged by the PNG\n specification "
+ "[first occurrence was at character position #%d]\n",
+ (unsigned)p[result], (p[result] == 27)? "strongly " : "",
+ result+1);
+ fflush(stderr);
+#ifdef FORBID_LATIN1_CTRL
+ wpng_info.have_text &= ~TEXT_AUTHOR;
+ valid = FALSE;
+#else
+ if (p[result] == 27) { /* escape character */
+ wpng_info.have_text &= ~TEXT_AUTHOR;
+ valid = FALSE;
+ }
+#endif
+ }
+ }
+ } while (!valid);
+
+ do {
+ valid = TRUE;
+ p = textbuf + TEXT_DESC_OFFSET;
+ fprintf(stderr, " Description (up to 9 lines):\n");
+ for (i = 1; i < 10; ++i) {
+ fprintf(stderr, " [%d] ", i);
+ fflush(stderr);
+ if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1)
+ p += len; /* now points at NULL; char before is newline */
+ else
+ break;
+ }
+ if ((len = p - (textbuf + TEXT_DESC_OFFSET)) > 1) {
+ if (p[-1] == '\n') {
+ p[-1] = '\0';
+ --len;
+ }
+ wpng_info.desc = textbuf + TEXT_DESC_OFFSET;
+ wpng_info.have_text |= TEXT_DESC;
+ p = textbuf + TEXT_DESC_OFFSET;
+ if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) {
+ fprintf(stderr, " " PROGNAME " warning: character code"
+ " %u is %sdiscouraged by the PNG\n specification "
+ "[first occurrence was at character position #%d]\n",
+ (unsigned)p[result], (p[result] == 27)? "strongly " : "",
+ result+1);
+ fflush(stderr);
+#ifdef FORBID_LATIN1_CTRL
+ wpng_info.have_text &= ~TEXT_DESC;
+ valid = FALSE;
+#else
+ if (p[result] == 27) { /* escape character */
+ wpng_info.have_text &= ~TEXT_DESC;
+ valid = FALSE;
+ }
+#endif
+ }
+ }
+ } while (!valid);
+
+ do {
+ valid = TRUE;
+ p = textbuf + TEXT_COPY_OFFSET;
+ fprintf(stderr, " Copyright: ");
+ fflush(stderr);
+ if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) {
+ if (p[len-1] == '\n')
+ p[--len] = '\0';
+ wpng_info.copyright = p;
+ wpng_info.have_text |= TEXT_COPY;
+ if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) {
+ fprintf(stderr, " " PROGNAME " warning: character code"
+ " %u is %sdiscouraged by the PNG\n specification "
+ "[first occurrence was at character position #%d]\n",
+ (unsigned)p[result], (p[result] == 27)? "strongly " : "",
+ result+1);
+ fflush(stderr);
+#ifdef FORBID_LATIN1_CTRL
+ wpng_info.have_text &= ~TEXT_COPY;
+ valid = FALSE;
+#else
+ if (p[result] == 27) { /* escape character */
+ wpng_info.have_text &= ~TEXT_COPY;
+ valid = FALSE;
+ }
+#endif
+ }
+ }
+ } while (!valid);
+
+ do {
+ valid = TRUE;
+ p = textbuf + TEXT_EMAIL_OFFSET;
+ fprintf(stderr, " E-mail: ");
+ fflush(stderr);
+ if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) {
+ if (p[len-1] == '\n')
+ p[--len] = '\0';
+ wpng_info.email = p;
+ wpng_info.have_text |= TEXT_EMAIL;
+ if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) {
+ fprintf(stderr, " " PROGNAME " warning: character code"
+ " %u is %sdiscouraged by the PNG\n specification "
+ "[first occurrence was at character position #%d]\n",
+ (unsigned)p[result], (p[result] == 27)? "strongly " : "",
+ result+1);
+ fflush(stderr);
+#ifdef FORBID_LATIN1_CTRL
+ wpng_info.have_text &= ~TEXT_EMAIL;
+ valid = FALSE;
+#else
+ if (p[result] == 27) { /* escape character */
+ wpng_info.have_text &= ~TEXT_EMAIL;
+ valid = FALSE;
+ }
+#endif
+ }
+ }
+ } while (!valid);
+
+ do {
+ valid = TRUE;
+ p = textbuf + TEXT_URL_OFFSET;
+ fprintf(stderr, " URL: ");
+ fflush(stderr);
+ if (FGETS(p, 74, keybd) && (len = strlen(p)) > 1) {
+ if (p[len-1] == '\n')
+ p[--len] = '\0';
+ wpng_info.url = p;
+ wpng_info.have_text |= TEXT_URL;
+ if ((result = wpng_isvalid_latin1((uch *)p, len)) >= 0) {
+ fprintf(stderr, " " PROGNAME " warning: character code"
+ " %u is %sdiscouraged by the PNG\n specification "
+ "[first occurrence was at character position #%d]\n",
+ (unsigned)p[result], (p[result] == 27)? "strongly " : "",
+ result+1);
+ fflush(stderr);
+#ifdef FORBID_LATIN1_CTRL
+ wpng_info.have_text &= ~TEXT_URL;
+ valid = FALSE;
+#else
+ if (p[result] == 27) { /* escape character */
+ wpng_info.have_text &= ~TEXT_URL;
+ valid = FALSE;
+ }
+#endif
+ }
+ }
+ } while (!valid);
+
+#ifndef DOS_OS2_W32
+ fclose(keybd);
+#endif
+
+ } else if (text) {
+ fprintf(stderr, PROGNAME ": unable to allocate memory for text\n");
+ text = FALSE;
+ wpng_info.have_text = 0;
+ }
+
+
+ /* allocate libpng stuff, initialize transformations, write pre-IDAT data */
+
+ if ((rc = writepng_init(&wpng_info)) != 0) {
+ switch (rc) {
+ case 2:
+ fprintf(stderr, PROGNAME
+ ": libpng initialization problem (longjmp)\n");
+ break;
+ case 4:
+ fprintf(stderr, PROGNAME ": insufficient memory\n");
+ break;
+ case 11:
+ fprintf(stderr, PROGNAME
+ ": internal logic error (unexpected PNM type)\n");
+ break;
+ default:
+ fprintf(stderr, PROGNAME
+ ": unknown writepng_init() error\n");
+ break;
+ }
+ exit(rc);
+ }
+
+
+ /* free textbuf, since it's a completely local variable and all text info
+ * has just been written to the PNG file */
+
+ if (text && textbuf) {
+ free(textbuf);
+ textbuf = NULL;
+ }
+
+
+ /* calculate rowbytes on basis of image type; note that this becomes much
+ * more complicated if we choose to support PBM type, ASCII PNM types, or
+ * 16-bit-per-sample binary data [currently not an official NetPBM type] */
+
+ if (wpng_info.pnmtype == 5)
+ rowbytes = wpng_info.width;
+ else if (wpng_info.pnmtype == 6)
+ rowbytes = wpng_info.width * 3;
+ else /* if (wpng_info.pnmtype == 8) */
+ rowbytes = wpng_info.width * 4;
+
+
+ /* read and write the image, either in its entirety (if writing interlaced
+ * PNG) or row by row (if non-interlaced) */
+
+ fprintf(stderr, "Encoding image data...\n");
+ fflush(stderr);
+
+ if (wpng_info.interlaced) {
+ long i;
+ ulg bytes;
+ ulg image_bytes = rowbytes * wpng_info.height; /* overflow? */
+
+ wpng_info.image_data = (uch *)malloc(image_bytes);
+ wpng_info.row_pointers = (uch **)malloc(wpng_info.height*sizeof(uch *));
+ if (wpng_info.image_data == NULL || wpng_info.row_pointers == NULL) {
+ fprintf(stderr, PROGNAME ": insufficient memory for image data\n");
+ writepng_cleanup(&wpng_info);
+ wpng_cleanup();
+ exit(5);
+ }
+ for (i = 0; i < wpng_info.height; ++i)
+ wpng_info.row_pointers[i] = wpng_info.image_data + i*rowbytes;
+ bytes = fread(wpng_info.image_data, 1, image_bytes, wpng_info.infile);
+ if (bytes != image_bytes) {
+ fprintf(stderr, PROGNAME ": expected %lu bytes, got %lu bytes\n",
+ image_bytes, bytes);
+ fprintf(stderr, " (continuing anyway)\n");
+ }
+ if (writepng_encode_image(&wpng_info) != 0) {
+ fprintf(stderr, PROGNAME
+ ": libpng problem (longjmp) while writing image data\n");
+ writepng_cleanup(&wpng_info);
+ wpng_cleanup();
+ exit(2);
+ }
+
+ } else /* not interlaced: write progressively (row by row) */ {
+ long j;
+ ulg bytes;
+
+ wpng_info.image_data = (uch *)malloc(rowbytes);
+ if (wpng_info.image_data == NULL) {
+ fprintf(stderr, PROGNAME ": insufficient memory for row data\n");
+ writepng_cleanup(&wpng_info);
+ wpng_cleanup();
+ exit(5);
+ }
+ error = 0;
+ for (j = wpng_info.height; j > 0L; --j) {
+ bytes = fread(wpng_info.image_data, 1, rowbytes, wpng_info.infile);
+ if (bytes != rowbytes) {
+ fprintf(stderr, PROGNAME
+ ": expected %lu bytes, got %lu bytes (row %ld)\n", rowbytes,
+ bytes, wpng_info.height-j);
+ ++error;
+ break;
+ }
+ if (writepng_encode_row(&wpng_info) != 0) {
+ fprintf(stderr, PROGNAME
+ ": libpng problem (longjmp) while writing row %ld\n",
+ wpng_info.height-j);
+ ++error;
+ break;
+ }
+ }
+ if (error) {
+ writepng_cleanup(&wpng_info);
+ wpng_cleanup();
+ exit(2);
+ }
+ if (writepng_encode_finish(&wpng_info) != 0) {
+ fprintf(stderr, PROGNAME ": error on final libpng call\n");
+ writepng_cleanup(&wpng_info);
+ wpng_cleanup();
+ exit(2);
+ }
+ }
+
+
+ /* OK, we're done (successfully): clean up all resources and quit */
+
+ fprintf(stderr, "Done.\n");
+ fflush(stderr);
+
+ writepng_cleanup(&wpng_info);
+ wpng_cleanup();
+
+ return 0;
+}
+
+
+
+
+
+static int wpng_isvalid_latin1(uch *p, int len)
+{
+ int i, result = -1;
+
+ for (i = 0; i < len; ++i) {
+ if (p[i] == 10 || (p[i] > 31 && p[i] < 127) || p[i] > 160)
+ continue; /* character is completely OK */
+ if (result < 0 || (p[result] != 27 && p[i] == 27))
+ result = i; /* mark location of first questionable one */
+ } /* or of first escape character (bad) */
+
+ return result;
+}
+
+
+
+
+
+static void wpng_cleanup(void)
+{
+ if (wpng_info.outfile) {
+ fclose(wpng_info.outfile);
+ wpng_info.outfile = NULL;
+ }
+
+ if (wpng_info.infile) {
+ fclose(wpng_info.infile);
+ wpng_info.infile = NULL;
+ }
+
+ if (wpng_info.image_data) {
+ free(wpng_info.image_data);
+ wpng_info.image_data = NULL;
+ }
+
+ if (wpng_info.row_pointers) {
+ free(wpng_info.row_pointers);
+ wpng_info.row_pointers = NULL;
+ }
+}
+
+
+
+
+#ifdef DOS_OS2_W32
+
+static char *dos_kbd_gets(char *buf, int len)
+{
+ int ch, count=0;
+
+ do {
+ buf[count++] = ch = getche();
+ } while (ch != '\r' && count < len-1);
+
+ buf[count--] = '\0'; /* terminate string */
+ if (buf[count] == '\r') /* Enter key makes CR, so change to newline */
+ buf[count] = '\n';
+
+ fprintf(stderr, "\n"); /* Enter key does *not* cause a newline */
+ fflush(stderr);
+
+ return buf;
+}
+
+#endif /* DOS_OS2_W32 */
diff --git a/contrib/gregbook/writepng.c b/contrib/gregbook/writepng.c
new file mode 100644
index 0000000..e6d81ea
--- /dev/null
+++ b/contrib/gregbook/writepng.c
@@ -0,0 +1,392 @@
+/*---------------------------------------------------------------------------
+
+ wpng - simple PNG-writing program writepng.c
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+
+#include <stdlib.h> /* for exit() prototype */
+
+#include "png.h" /* libpng header; includes zlib.h and setjmp.h */
+#include "writepng.h" /* typedefs, common macros, public prototypes */
+
+
+/* local prototype */
+
+static void writepng_error_handler(png_structp png_ptr, png_const_charp msg);
+
+
+
+void writepng_version_info(void)
+{
+ fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n",
+ PNG_LIBPNG_VER_STRING, png_libpng_ver);
+ fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n",
+ ZLIB_VERSION, zlib_version);
+}
+
+
+
+
+/* returns 0 for success, 2 for libpng problem, 4 for out of memory, 11 for
+ * unexpected pnmtype; note that outfile might be stdout */
+
+int writepng_init(mainprog_info *mainprog_ptr)
+{
+ png_structp png_ptr; /* note: temporary variables! */
+ png_infop info_ptr;
+ int color_type, interlace_type;
+
+
+ /* could also replace libpng warning-handler (final NULL), but no need: */
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
+ writepng_error_handler, NULL);
+ if (!png_ptr)
+ return 4; /* out of memory */
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_write_struct(&png_ptr, NULL);
+ return 4; /* out of memory */
+ }
+
+
+ /* setjmp() must be called in every function that calls a PNG-writing
+ * libpng function, unless an alternate error handler was installed--
+ * but compatible error handlers must either use longjmp() themselves
+ * (as in this program) or exit immediately, so here we go: */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 2;
+ }
+
+
+ /* make sure outfile is (re)opened in BINARY mode */
+
+ png_init_io(png_ptr, mainprog_ptr->outfile);
+
+
+ /* set the compression levels--in general, always want to leave filtering
+ * turned on (except for palette images) and allow all of the filters,
+ * which is the default; want 32K zlib window, unless entire image buffer
+ * is 16K or smaller (unknown here)--also the default; usually want max
+ * compression (NOT the default); and remaining compression flags should
+ * be left alone */
+
+ png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
+/*
+ >> this is default for no filtering; Z_FILTERED is default otherwise:
+ png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
+ >> these are all defaults:
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+ */
+
+
+ /* set the image parameters appropriately */
+
+ if (mainprog_ptr->pnmtype == 5)
+ color_type = PNG_COLOR_TYPE_GRAY;
+ else if (mainprog_ptr->pnmtype == 6)
+ color_type = PNG_COLOR_TYPE_RGB;
+ else if (mainprog_ptr->pnmtype == 8)
+ color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ else {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 11;
+ }
+
+ interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 :
+ PNG_INTERLACE_NONE;
+
+ png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height,
+ mainprog_ptr->sample_depth, color_type, interlace_type,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ if (mainprog_ptr->gamma > 0.0)
+ png_set_gAMA(png_ptr, info_ptr, mainprog_ptr->gamma);
+
+ if (mainprog_ptr->have_bg) { /* we know it's RGBA, not gray+alpha */
+ png_color_16 background;
+
+ background.red = mainprog_ptr->bg_red;
+ background.green = mainprog_ptr->bg_green;
+ background.blue = mainprog_ptr->bg_blue;
+ png_set_bKGD(png_ptr, info_ptr, &background);
+ }
+
+ if (mainprog_ptr->have_time) {
+ png_time modtime;
+
+ png_convert_from_time_t(&modtime, mainprog_ptr->modtime);
+ png_set_tIME(png_ptr, info_ptr, &modtime);
+ }
+
+ if (mainprog_ptr->have_text) {
+ png_text text[6];
+ int num_text = 0;
+
+ if (mainprog_ptr->have_text & TEXT_TITLE) {
+ text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ text[num_text].key = "Title";
+ text[num_text].text = mainprog_ptr->title;
+ ++num_text;
+ }
+ if (mainprog_ptr->have_text & TEXT_AUTHOR) {
+ text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ text[num_text].key = "Author";
+ text[num_text].text = mainprog_ptr->author;
+ ++num_text;
+ }
+ if (mainprog_ptr->have_text & TEXT_DESC) {
+ text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ text[num_text].key = "Description";
+ text[num_text].text = mainprog_ptr->desc;
+ ++num_text;
+ }
+ if (mainprog_ptr->have_text & TEXT_COPY) {
+ text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ text[num_text].key = "Copyright";
+ text[num_text].text = mainprog_ptr->copyright;
+ ++num_text;
+ }
+ if (mainprog_ptr->have_text & TEXT_EMAIL) {
+ text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ text[num_text].key = "E-mail";
+ text[num_text].text = mainprog_ptr->email;
+ ++num_text;
+ }
+ if (mainprog_ptr->have_text & TEXT_URL) {
+ text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ text[num_text].key = "URL";
+ text[num_text].text = mainprog_ptr->url;
+ ++num_text;
+ }
+ png_set_text(png_ptr, info_ptr, text, num_text);
+ }
+
+
+ /* write all chunks up to (but not including) first IDAT */
+
+ png_write_info(png_ptr, info_ptr);
+
+
+ /* if we wanted to write any more text info *after* the image data, we
+ * would set up text struct(s) here and call png_set_text() again, with
+ * just the new data; png_set_tIME() could also go here, but it would
+ * have no effect since we already called it above (only one tIME chunk
+ * allowed) */
+
+
+ /* set up the transformations: for now, just pack low-bit-depth pixels
+ * into bytes (one, two or four pixels per byte) */
+
+ png_set_packing(png_ptr);
+/* png_set_shift(png_ptr, &sig_bit); to scale low-bit-depth values */
+
+
+ /* make sure we save our pointers for use in writepng_encode_image() */
+
+ mainprog_ptr->png_ptr = png_ptr;
+ mainprog_ptr->info_ptr = info_ptr;
+
+
+ /* OK, that's all we need to do for now; return happy */
+
+ return 0;
+}
+
+
+
+
+
+/* returns 0 for success, 2 for libpng (longjmp) problem */
+
+int writepng_encode_image(mainprog_info *mainprog_ptr)
+{
+ png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
+ png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
+
+
+ /* as always, setjmp() must be called in every function that calls a
+ * PNG-writing libpng function */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ mainprog_ptr->png_ptr = NULL;
+ mainprog_ptr->info_ptr = NULL;
+ return 2;
+ }
+
+
+ /* and now we just write the whole image; libpng takes care of interlacing
+ * for us */
+
+ png_write_image(png_ptr, mainprog_ptr->row_pointers);
+
+
+ /* since that's it, we also close out the end of the PNG file now--if we
+ * had any text or time info to write after the IDATs, second argument
+ * would be info_ptr, but we optimize slightly by sending NULL pointer: */
+
+ png_write_end(png_ptr, NULL);
+
+ return 0;
+}
+
+
+
+
+
+/* returns 0 if succeeds, 2 if libpng problem */
+
+int writepng_encode_row(mainprog_info *mainprog_ptr) /* NON-interlaced only! */
+{
+ png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
+ png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
+
+
+ /* as always, setjmp() must be called in every function that calls a
+ * PNG-writing libpng function */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ mainprog_ptr->png_ptr = NULL;
+ mainprog_ptr->info_ptr = NULL;
+ return 2;
+ }
+
+
+ /* image_data points at our one row of image data */
+
+ png_write_row(png_ptr, mainprog_ptr->image_data);
+
+ return 0;
+}
+
+
+
+
+
+/* returns 0 if succeeds, 2 if libpng problem */
+
+int writepng_encode_finish(mainprog_info *mainprog_ptr) /* NON-interlaced! */
+{
+ png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
+ png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
+
+
+ /* as always, setjmp() must be called in every function that calls a
+ * PNG-writing libpng function */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ mainprog_ptr->png_ptr = NULL;
+ mainprog_ptr->info_ptr = NULL;
+ return 2;
+ }
+
+
+ /* close out PNG file; if we had any text or time info to write after
+ * the IDATs, second argument would be info_ptr: */
+
+ png_write_end(png_ptr, NULL);
+
+ return 0;
+}
+
+
+
+
+
+void writepng_cleanup(mainprog_info *mainprog_ptr)
+{
+ png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
+ png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
+
+ if (png_ptr && info_ptr)
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+}
+
+
+
+
+
+static void writepng_error_handler(png_structp png_ptr, png_const_charp msg)
+{
+ mainprog_info *mainprog_ptr;
+
+ /* This function, aside from the extra step of retrieving the "error
+ * pointer" (below) and the fact that it exists within the application
+ * rather than within libpng, is essentially identical to libpng's
+ * default error handler. The second point is critical: since both
+ * setjmp() and longjmp() are called from the same code, they are
+ * guaranteed to have compatible notions of how big a jmp_buf is,
+ * regardless of whether _BSD_SOURCE or anything else has (or has not)
+ * been defined. */
+
+ fprintf(stderr, "writepng libpng error: %s\n", msg);
+ fflush(stderr);
+
+ mainprog_ptr = png_get_error_ptr(png_ptr);
+ if (mainprog_ptr == NULL) { /* we are completely hosed now */
+ fprintf(stderr,
+ "writepng severe error: jmpbuf not recoverable; terminating.\n");
+ fflush(stderr);
+ exit(99);
+ }
+
+ longjmp(mainprog_ptr->jmpbuf, 1);
+}
diff --git a/contrib/gregbook/writepng.h b/contrib/gregbook/writepng.h
new file mode 100644
index 0000000..78b966b
--- /dev/null
+++ b/contrib/gregbook/writepng.h
@@ -0,0 +1,133 @@
+/*---------------------------------------------------------------------------
+
+ wpng - simple PNG-writing program writepng.h
+
+ ---------------------------------------------------------------------------
+
+ Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
+
+ This software is provided "as is," without warranty of any kind,
+ express or implied. In no event shall the author or contributors
+ be held liable for any damages arising in any way from the use of
+ this software.
+
+ The contents of this file are DUAL-LICENSED. You may modify and/or
+ redistribute this software according to the terms of one of the
+ following two licenses (at your option):
+
+
+ LICENSE 1 ("BSD-like with advertising clause"):
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, disclaimer, and this list of conditions.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, disclaimer, and this list of conditions in the documenta-
+ tion and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgment:
+
+ This product includes software developed by Greg Roelofs
+ and contributors for the book, "PNG: The Definitive Guide,"
+ published by O'Reilly and Associates.
+
+
+ LICENSE 2 (GNU GPL v2 or later):
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b)? (a) : (b))
+# define MIN(a,b) ((a) < (b)? (a) : (b))
+#endif
+
+#ifdef DEBUG
+# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);}
+#else
+# define Trace(x) ;
+#endif
+
+#define TEXT_TITLE 0x01
+#define TEXT_AUTHOR 0x02
+#define TEXT_DESC 0x04
+#define TEXT_COPY 0x08
+#define TEXT_EMAIL 0x10
+#define TEXT_URL 0x20
+
+#define TEXT_TITLE_OFFSET 0
+#define TEXT_AUTHOR_OFFSET 72
+#define TEXT_COPY_OFFSET (2*72)
+#define TEXT_EMAIL_OFFSET (3*72)
+#define TEXT_URL_OFFSET (4*72)
+#define TEXT_DESC_OFFSET (5*72)
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+typedef struct _mainprog_info {
+ double gamma;
+ long width;
+ long height;
+ time_t modtime;
+ FILE *infile;
+ FILE *outfile;
+ void *png_ptr;
+ void *info_ptr;
+ uch *image_data;
+ uch **row_pointers;
+ char *title;
+ char *author;
+ char *desc;
+ char *copyright;
+ char *email;
+ char *url;
+ int filter; /* command-line-filter flag, not PNG row filter! */
+ int pnmtype;
+ int sample_depth;
+ int interlaced;
+ int have_bg;
+ int have_time;
+ int have_text;
+ jmp_buf jmpbuf;
+ uch bg_red;
+ uch bg_green;
+ uch bg_blue;
+} mainprog_info;
+
+
+/* prototypes for public functions in writepng.c */
+
+void writepng_version_info(void);
+
+int writepng_init(mainprog_info *mainprog_ptr);
+
+int writepng_encode_image(mainprog_info *mainprog_ptr);
+
+int writepng_encode_row(mainprog_info *mainprog_ptr);
+
+int writepng_encode_finish(mainprog_info *mainprog_ptr);
+
+void writepng_cleanup(mainprog_info *mainprog_ptr);
diff --git a/contrib/pngminim/decoder/README b/contrib/pngminim/decoder/README
new file mode 100644
index 0000000..4f71082
--- /dev/null
+++ b/contrib/pngminim/decoder/README
@@ -0,0 +1,6 @@
+This demonstrates the use of PNG_USER_CONFIG and pngusr.h
+
+To build a minimal read-only decoder, run
+ gather.sh # to collect needed files from pngminus, libpng, and zlib
+ make -f makefile.std
+
diff --git a/contrib/pngminim/decoder/gather.sh b/contrib/pngminim/decoder/gather.sh
new file mode 100755
index 0000000..e28ddaf
--- /dev/null
+++ b/contrib/pngminim/decoder/gather.sh
@@ -0,0 +1,8 @@
+cp ../../pngminus/png2pnm.c pngm2pnm.c
+cp ../../../*.h .
+cp ../../../*.c .
+rm example.c pnggccrd.c pngvcrd.c pngtest.c pngpread.c
+# change the following 2 lines if zlib is somewhere else
+cp ../../../../zlib/*.h .
+cp ../../../../zlib/*.c .
+rm minigzip.c example.c compress.c deflate.c
diff --git a/contrib/pngminim/decoder/makefile.std b/contrib/pngminim/decoder/makefile.std
new file mode 100644
index 0000000..27e04cb
--- /dev/null
+++ b/contrib/pngminim/decoder/makefile.std
@@ -0,0 +1,44 @@
+# Makefile for PngMinus (pngm2pnm)
+# Linux / Unix
+
+#CC=cc
+CC=gcc
+LD=$(CC)
+
+RM=rm -f
+
+CFLAGS=-DPNG_USER_CONFIG -DNO_GZCOMPRESS -DNO_GZIP \
+ -DdeflateParams\(a,b,c\)=Z_OK -I. -O1
+
+C=.c
+O=.o
+L=.a
+E=
+
+ZOBJS = adler32$(O) crc32$(O) gzio$(O) \
+ infback$(O) inffast$(O) inflate$(O) inftrees$(O) \
+ trees$(O) uncompr$(O) zutil$(O)
+
+OBJS = pngm2pnm$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \
+ pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \
+ pngset$(O) pngtrans$(O) $(ZOBJS)
+
+# implicit make rules -------------------------------------------------------
+
+.c$(O): png.h pngconf.h pngusr.h zlib.h
+ $(CC) -c $(CFLAGS) $<
+
+# dependencies
+
+all: pngm2pnm$(E)
+
+pngm2pnm$(E): $(OBJS)
+ $(LD) -o pngm2pnm$(E) $(OBJS)
+ strip pngm2pnm$(E)
+
+clean:
+ $(RM) pngm2pnm$(O)
+ $(RM) pngm2pnm$(E)
+ $(RM) $(OBJS)
+
+# End of makefile for pngm2pnm
diff --git a/contrib/pngminim/decoder/pngusr.h b/contrib/pngminim/decoder/pngusr.h
new file mode 100644
index 0000000..f94b83a
--- /dev/null
+++ b/contrib/pngminim/decoder/pngusr.h
@@ -0,0 +1,67 @@
+/* minrdpngconf.h: headers to make a minimal png-read-only library
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 2007 Glenn Randers-Pehrson
+ * Derived from pngcrush.h, Copyright 1998-2007, Glenn Randers-Pehrson
+ */
+
+#ifndef MINRDPNGCONF_H
+#define MINRDPNGCONF_H
+
+#define PNG_NO_GLOBAL_ARRAYS
+
+#define PNG_NO_WARNINGS
+#define png_warning(s1,s2) ""
+#define png_chunk_warning(s1,s2) ""
+#define PNG_NO_ERROR_TEXT
+#define png_error(s1,s2) png_err(s1)
+#define png_chunk_error(s1,s2) png_err(s1)
+
+#define PNG_NO_ASSEMBLER_CODE
+#define PNG_NO_OPTIMIZED_CODE
+#define PNG_NO_READ_GAMMA
+#define PNG_NO_READ_BACKGROUND
+#define PNG_NO_READ_DITHER
+#define PNG_NO_READ_INVERT
+#define PNG_NO_READ_SHIFT
+#define PNG_NO_READ_PACK
+#define PNG_NO_READ_PACKSWAP
+#define PNG_NO_READ_FILLER
+#define PNG_NO_READ_SWAP_ALPHA
+#define PNG_NO_READ_INVERT_ALPHA
+#define PNG_NO_READ_RGB_TO_GRAY
+#define PNG_NO_READ_USER_TRANSFORM
+#define PNG_NO_READ_bKGD
+#define PNG_NO_READ_cHRM
+#define PNG_NO_READ_gAMA
+#define PNG_NO_READ_hIST
+#define PNG_NO_READ_iCCP
+#define PNG_NO_READ_pCAL
+#define PNG_NO_READ_pHYs
+#define PNG_NO_READ_sBIT
+#define PNG_NO_READ_sCAL
+#define PNG_NO_READ_sPLT
+#define PNG_NO_READ_TEXT
+#define PNG_NO_READ_tIME
+#define PNG_NO_READ_UNKNOWN_CHUNKS
+#define PNG_NO_READ_USER_CHUNKS
+#define PNG_NO_READ_EMPTY_PLTE
+#define PNG_NO_READ_OPT_PLTE
+#define PNG_NO_READ_STRIP_ALPHA
+#define PNG_NO_READ_oFFs
+#define PNG_NO_WARN_UNINITIALIZED_ROW
+
+#define PNG_NO_WRITE_SUPPORTED
+
+#define PNG_NO_INFO_IMAGE
+#define PNG_NO_USER_MEM
+#define PNG_NO_FIXED_POINT_SUPPORTED
+#define PNG_NO_MNG_FEATURES
+#define PNG_NO_USER_TRANSFORM_PTR
+#define PNG_NO_HANDLE_AS_UNKNOWN
+#define PNG_NO_CONSOLE_IO
+#define PNG_NO_ZALLOC_ZERO
+#define PNG_NO_ERROR_NUMBERS
+#define PNG_NO_EASY_ACCESS
+#define PNG_NO_PROGRESSIVE_READ
+
+#endif /* MINRDPNGCONF_H */
diff --git a/contrib/pngminim/encoder/README b/contrib/pngminim/encoder/README
new file mode 100644
index 0000000..4a68fc8
--- /dev/null
+++ b/contrib/pngminim/encoder/README
@@ -0,0 +1,6 @@
+This demonstrates the use of PNG_USER_CONFIG and pngusr.h
+
+To build a minimal write-only encoder, run
+ gather.sh # to collect needed files from pngminus, libpng, and zlib
+ make -f makefile.std
+
diff --git a/contrib/pngminim/encoder/dummy_inflate.c b/contrib/pngminim/encoder/dummy_inflate.c
new file mode 100644
index 0000000..1422edb
--- /dev/null
+++ b/contrib/pngminim/encoder/dummy_inflate.c
@@ -0,0 +1,27 @@
+#include "zlib.h"
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{ return Z_OK ; }
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{ return Z_OK ; }
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{ return Z_STREAM_ERROR ; }
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{ return Z_OK ; }
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{ return Z_STREAM_ERROR ; }
diff --git a/contrib/pngminim/encoder/gather.sh b/contrib/pngminim/encoder/gather.sh
new file mode 100755
index 0000000..7b0c803
--- /dev/null
+++ b/contrib/pngminim/encoder/gather.sh
@@ -0,0 +1,9 @@
+cp ../../pngminus/pnm2png.c pnm2pngm.c
+cp ../../../*.h .
+cp ../../../*.c .
+rm example.c pnggccrd.c pngvcrd.c pngtest.c pngr*.c
+# Change the next 2 lines if zlib is somewhere else.
+cp ../../../../zlib/*.h .
+cp ../../../../zlib/*.c .
+rm inf*.[ch]
+rm minigzip.c example.c
diff --git a/contrib/pngminim/encoder/makefile.std b/contrib/pngminim/encoder/makefile.std
new file mode 100644
index 0000000..1182b5b
--- /dev/null
+++ b/contrib/pngminim/encoder/makefile.std
@@ -0,0 +1,43 @@
+# Makefile for PngMinus (pnm2pngm)
+# Linux / Unix
+
+#CC=cc
+CC=gcc
+LD=$(CC)
+
+RM=rm -f
+
+CFLAGS=-DPNG_USER_CONFIG -DNO_GZIP -I. -O1
+
+C=.c
+O=.o
+L=.a
+E=
+
+ZOBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) gzio$(O) \
+ dummy_inflate$(O) \
+ trees$(O) uncompr$(O) zutil$(O)
+
+OBJS = pnm2pngm$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \
+ pngset$(O) pngtrans$(O) pngwio$(O) pngwrite$(O) \
+ pngwtran$(O) pngwutil$(O) $(ZOBJS)
+
+# implicit make rules -------------------------------------------------------
+
+.c$(O): png.h pngconf.h pngusr.h zlib.h
+ $(CC) -c $(CFLAGS) $<
+
+# dependencies
+
+all: pnm2pngm$(E)
+
+pnm2pngm$(E): $(OBJS)
+ $(LD) -o pnm2pngm$(E) $(OBJS)
+ strip pnm2pngm$(E)
+
+clean:
+ $(RM) pnm2pngm$(O)
+ $(RM) pnm2pngm$(E)
+ $(RM) $(OBJS)
+
+# End of makefile for pnm2pngm
diff --git a/contrib/pngminim/encoder/pngusr.h b/contrib/pngminim/encoder/pngusr.h
new file mode 100644
index 0000000..904673a
--- /dev/null
+++ b/contrib/pngminim/encoder/pngusr.h
@@ -0,0 +1,66 @@
+/* minwrpngconf.h: headers to make a minimal png-write-only library
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 2007 Glenn Randers-Pehrson
+ * Derived from pngcrush.h, Copyright 1998-2007, Glenn Randers-Pehrson
+ */
+
+#ifndef MINWRPNGCONF_H
+#define MINWRPNGCONF_H
+
+#define PNG_NO_GLOBAL_ARRAYS
+
+#define PNG_NO_READ_SUPPORTED
+
+#define PNG_NO_WARNINGS
+#define png_warning(s1,s2) ""
+#define png_chunk_warning(s1,s2) ""
+#define PNG_NO_ERROR_TEXT
+#define png_error(s1,s2) png_err(s1)
+#define png_chunk_error(s1,s2) png_err(s1)
+
+#define PNG_NO_WRITE_BACKGROUND
+#define PNG_NO_WRITE_GAMMA
+#define PNG_NO_WRITE_DITHER
+#define PNG_NO_WRITE_INVERT
+#define PNG_NO_WRITE_SHIFT
+#define PNG_NO_WRITE_PACK
+#define PNG_NO_WRITE_PACKSWAP
+#define PNG_NO_WRITE_FILLER
+#define PNG_NO_WRITE_SWAP_ALPHA
+#define PNG_NO_WRITE_INVERT_ALPHA
+#define PNG_NO_WRITE_RGB_TO_GRAY
+#define PNG_NO_WRITE_USER_TRANSFORM
+#define PNG_NO_WRITE_bKGD
+#define PNG_NO_WRITE_cHRM
+#define PNG_NO_WRITE_gAMA
+#define PNG_NO_WRITE_sRGB
+#define PNG_NO_WRITE_hIST
+#define PNG_NO_WRITE_iCCP
+#define PNG_NO_WRITE_oFFs
+#define PNG_NO_WRITE_pCAL
+#define PNG_NO_WRITE_pHYs
+#define PNG_NO_WRITE_sBIT
+#define PNG_NO_WRITE_sCAL
+#define PNG_NO_WRITE_sPLT
+#define PNG_NO_WRITE_TEXT
+#define PNG_NO_WRITE_tIME
+#define PNG_NO_WRITE_UNKNOWN_CHUNKS
+#define PNG_NO_WRITE_USER_CHUNKS
+#define PNG_NO_WRITE_EMPTY_PLTE
+#define PNG_NO_WRITE_OPT_PLTE
+#define PNG_NO_WRITE_FILTER
+#define PNG_NO_WRITE_WEIGHTED_FILTER
+#define PNG_NO_WRITE_INTERLACING_SUPPORTED
+
+#define PNG_NO_INFO_IMAGE
+#define PNG_NO_USER_MEM
+#define PNG_NO_FIXED_POINT_SUPPORTED
+#define PNG_NO_MNG_FEATURES
+#define PNG_NO_USER_TRANSFORM_PTR
+#define PNG_NO_HANDLE_AS_UNKNOWN
+#define PNG_NO_CONSOLE_IO
+#define PNG_NO_ZALLOC_ZERO
+#define PNG_NO_ERROR_NUMBERS
+#define PNG_NO_EASY_ACCESS
+
+#endif /* MINWRPNGCONF_H */
diff --git a/contrib/pngminus/README b/contrib/pngminus/README
new file mode 100644
index 0000000..bbe7407
--- /dev/null
+++ b/contrib/pngminus/README
@@ -0,0 +1,153 @@
+PngMinus
+--------
+(copyright Willem van Schaik, 1999)
+
+
+License
+-------
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear in
+supporting documentation. This software is provided "as is" without
+express or implied warranty.
+
+
+Some history
+------------
+Soon after the creation of PNG in 1995, the need was felt for a set of
+pnmtopng / pngtopnm utilities. Independantly Alexander Lehmann and I
+(Willem van Schaik) started such a project. Luckily we discovered this
+and merged the two together into pnmtopng.tar.gz, which is available
+from a/o ftp://ftp.simplesystems.org/pub/libpng/png/.
+
+These two utilities have many, many options and make use of most of the
+features of PNG, like gamma, alpha, sbit, text-chunks, etc. This makes
+the utilities quite complex and by now not anymore very maintainable.
+When we wrote these programs, libpng was still in an early stage.
+Therefore, lots of the functionality that we put in our software can now
+be done using transform-functions in libpng.
+
+Finally, to compile these programs, you need to have installed and
+compiled three libraries: libpng, zlib and netpbm. Especially the latter
+makes the whole setup a bit bulky. But that's unavoidable given the many
+features of pnmtopng.
+
+
+What now
+--------
+At this moment libpng is in a very stable state and can do much of the
+work done in pnmtopng. Also, pnmtopng needs to be upgraded to the new
+interface of libpng. Hence, it is time for a rewrite from the ground up
+of pnmtopng and pngtopnm. This will happen in the near future (stay
+tuned). The new package will get a different name to distinguish it from
+the old one: PngPlus.
+
+To experiment a bit with the new interface of libpng, I started off with
+a small prototype that contains only the basic functionality. It doesn't
+have any of the options to read or write special chunks and it will do
+no gamma correction. But this makes it also a simple program that is
+quite easy to understand and can serve well as a template for other
+software developments. (By now there are of course a couple of programs,
+like Greg Roelofs' rpng/wpng, that can be used just as good.)
+
+
+Can and can not
+---------------
+As this is the small brother of the future PngPlus, I called this fellow
+PngMinus. Because I started this development in good-old Turbo-C, I
+avoided the use the netpbm library, which requires DOS extenders. Again,
+another reason to call it PngMinus (minus netpbm :-). So, part of the
+program are some elementary routines to read / write pgm- and ppm-files.
+It does not read b&w pbm-files.
+
+The downside of this approach is that you can not use them on images
+that require blocks of memory bigger than 64k (the DOS version). For
+larger images you will get an out-of-memory error.
+
+As said before, PngMinus doesn't correct for gamma. When reading
+png-files you can do this just as well by piping the output of png2pnm
+to pnmgamma, one of the standard PbmPlus tools. This same scenario will
+most probably also be followed in the full-blown future PngPlus, with
+the addition of course of the possibility to create gamma-chunks when
+writing png-files.
+
+On the other hand it supports alpha-channels. When reading a png-image
+you can write the alpha-channel into a pgm-file. And when creating an
+RGB+A png-image, you just combine a ppm-file with a corresponding
+pgm-file containing the alpha-channel. When reading, transparency chunks
+are converted into an alpha-channel and from there on treated the same
+way.
+
+Finally you can opt for writing ascii or binary pgm- and ppm-files. When
+the bit-depth is 16, the format will always be ascii.
+
+
+Using it
+--------
+To distinguish them from pnmtopng and PngPlus, the utilities are named
+png2pnm and pnm2png (2 instead of to). The input- and output-files can
+be given as parameters or through redirection. Therefore the programs
+can be part of a pipe.
+
+To list the options type "png2pnm -h" or "pnm2png -h".
+
+
+Just like Scandinavian furniture
+--------------------------------
+You have to put it together yourself. I did test the software under
+MS-DOS with Turbo-C 3.0 and under RedHat Linux 4.2 with gcc. In both
+cases I used libpng-1.0.4 and zlib-1.1.3. Later versions should be OK,
+however some older libpng versions have a bug in pngmem.c when using
+Turbo-C 3.0 (see below).
+
+You can build it using one of the two makefiles (make -f makefile.###)
+or use the batch/script files pngminus.bat / pngminus.sh. This assumes
+that you have built the libraries in ../libpng and ../zlib. Using Linux,
+make sure that you have built libpng with makefile.std and not
+makefile.linux (also called .lnx in earlier versions of libpng). The
+latter creates a .so shared-library, while the PngMinus makefile assumes
+a normal .a static library.
+
+If you create a ../pngsuite directory and then store the basn####.png
+files from PngSuite (http://www.schaik.com/pngsuite/) in there, you can
+test in one go the proper functioning of PngMinus, see png2pnm.bat and
+pnm2png.bat (or the .sh versions).
+
+
+Warranty
+-------
+Please, remember that this was just a small experiment to learn a few
+things. It will have many unforeseen features <vbg>. Who said bugs? Use
+it when you are in need for something simple or when you want to start
+developing your own stuff.
+
+
+The Turbo bug
+-------------
+** pngmem.old
+ hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
+ hptr += 16L;
+** pngmem.c
+ hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
+ hptr = hptr + 16L;
+**
+
+** pngmem.old
+ png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
+ hptr += (png_uint_32)65536L;
+** pngmem.c
+ png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
+ hptr = hptr + 65536L;
+**
+
+
+The end
+-------
+Willem van Schaik
+mailto:willem@schaik.com
+http://www.schaik.com/png/
+-------
+Oct 1999
+
diff --git a/contrib/pngminus/makefile.std b/contrib/pngminus/makefile.std
new file mode 100644
index 0000000..2fb061b
--- /dev/null
+++ b/contrib/pngminus/makefile.std
@@ -0,0 +1,65 @@
+# Makefile for PngMinus (png2pnm and pnm2png)
+# Linux / Unix
+
+#CC=cc
+CC=gcc
+LD=$(CC)
+
+RM=rm -f
+
+#PNGPATH = /usr/local
+#PNGINC = -I$(PNGPATH)/include/libpng12
+#PNGLIB = -L$(PNGPATH)/lib -lpng12
+#PNGLIBS = $(PNGPATH)/lib/libpng12.a
+PNGINC = -I../..
+PNGLIB = -L../.. -lpng
+PNGLIBS = ../../libpng.a
+
+#ZPATH = /usr/local
+#ZINC = -I$(ZPATH)/include
+#ZLIB = -L$(ZPATH)/lib -lz
+#ZLIBS = $(ZPATH)/lib/libz.a
+ZINC = -I../../../zlib
+ZLIB = -L../../../zlib -lz
+ZLIBS = ../../../zlib/libz.a
+
+CFLAGS=-O3 $(PNGINC) $(ZINC)
+LDFLAGS=$(PNGLIB) $(ZLIB)
+LDFLAGSS=$(PNGLIBS) $(ZLIBS)
+C=.c
+O=.o
+L=.a
+E=
+
+# dependencies
+
+#all: png2pnm$(E) pnm2png$(E)
+all: png2pnm$(E) pnm2png$(E) png2pnm-static$(E) pnm2png-static$(E)
+
+png2pnm$(O): png2pnm$(C)
+ $(CC) -c $(CFLAGS) png2pnm$(C)
+
+png2pnm$(E): png2pnm$(O)
+ $(LD) -o png2pnm$(E) png2pnm$(O) $(LDFLAGS) -lm
+
+png2pnm-static$(E): png2pnm$(O)
+ $(LD) -o png2pnm-static$(E) png2pnm$(O) $(LDFLAGSS) -lm
+
+pnm2png$(O): pnm2png$(C)
+ $(CC) -c $(CFLAGS) pnm2png$(C)
+
+pnm2png$(E): pnm2png$(O)
+ $(LD) -o pnm2png$(E) pnm2png$(O) $(LDFLAGS) -lm
+
+pnm2png-static$(E): pnm2png$(O)
+ $(LD) -o pnm2png-static$(E) pnm2png$(O) $(LDFLAGSS) -lm
+
+clean:
+ $(RM) png2pnm$(O)
+ $(RM) pnm2png$(O)
+ $(RM) png2pnm$(E)
+ $(RM) pnm2png$(E)
+ $(RM) png2pnm-static$(E)
+ $(RM) pnm2png-static$(E)
+
+# End of makefile for png2pnm / pnm2png
diff --git a/contrib/pngminus/makefile.tc3 b/contrib/pngminus/makefile.tc3
new file mode 100644
index 0000000..404f18d
--- /dev/null
+++ b/contrib/pngminus/makefile.tc3
@@ -0,0 +1,38 @@
+# Makefile for PngMinus (png2pnm and pnm2png)
+# TurboC++ 3.0
+
+CC=tcc -Ic:\tc3\inc
+LD=tcc -Lc:\tc3\lib
+LB=tlib
+RM=del
+CP=copy
+MODEL=l
+CCFLAGS=-O -m$(MODEL) -I..\libpng -I..\zlib
+LDFLAGS=-m$(MODEL) -L..\libpng -L..\zlib
+C=.c
+O=.obj
+L=.lib
+E=.exe
+
+# dependencies
+
+all: png2pnm$(E) pnm2png$(E)
+
+png2pnm$(O): png2pnm$(C)
+ $(CC) -c $(CCFLAGS) png2pnm$(C)
+
+png2pnm$(E): png2pnm$(O)
+ $(LD) $(LDFLAGS) png2pnm$(O) libpng$(L) zlib$(L)
+
+pnm2png$(O): pnm2png$(C)
+ $(CC) -c $(CCFLAGS) pnm2png$(C)
+
+pnm2png$(E): pnm2png$(O)
+ $(LD) $(LDFLAGS) pnm2png$(O) libpng$(L) zlib$(L)
+
+clean:
+ $(RM) *$(O)
+ $(RM) *$(E)
+
+# End of makefile for png2pnm / pnm2png
+
diff --git a/contrib/pngminus/makevms.com b/contrib/pngminus/makevms.com
new file mode 100644
index 0000000..00561bc
--- /dev/null
+++ b/contrib/pngminus/makevms.com
@@ -0,0 +1,92 @@
+$!------------------------------------------------------------------------------
+$! make Contrib programs of libpng under OpenVMS
+$!
+$!
+$! Look for the compiler used
+$!
+$ zlibsrc = "[---.zlib]"
+$ ccopt="/include=(''zlibsrc',[--])"
+$ if f$getsyi("HW_MODEL").ge.1024
+$ then
+$ ccopt = "/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs.""
+$ then
+$ if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ if f$search("SYS$SYSTEM:VAXC.EXE").eqs.""
+$ then
+$ comp = "__gcc__=1"
+$ CC :== GCC
+$ else
+$ comp = "__vaxc__=1"
+$ endif
+$ else
+$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include:
+$ ccopt = "/decc/prefix=all"+ccopt
+$ comp = "__decc__=1"
+$ endif
+$ endif
+$ open/write lopt lib.opt
+$ write lopt "[--]libpng.olb/lib"
+$ write lopt "''zlibsrc'libz.olb/lib"
+$ close lopt
+$ open/write xopt x11.opt
+$ write xopt "sys$library:decw$xlibshr.exe/share"
+$ close xopt
+$ write sys$output "Compiling PNG contrib programs ..."
+$ write sys$output "Building pnm2png..."
+$ CALL MAKE pnm2png.OBJ "cc ''CCOPT' pnm2png" -
+ pnm2png.c
+$ call make pnm2png.exe -
+ "LINK pnm2png,lib.opt/opt" -
+ pnm2png.obj
+$ write sys$output "Building png2pnm..."
+$ CALL MAKE png2pnm.OBJ "cc ''CCOPT' png2pnm" -
+ png2pnm.c
+$ call make png2pnm.exe -
+ "LINK png2pnm,lib.opt/opt" -
+ png2pnm.obj
+$ exit
+$!
+$!
+$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8 What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$ Argument = P'arg
+$ If Argument .Eqs. "" Then Goto Exit
+$ El=0
+$Loop2:
+$ File = F$Element(El," ",Argument)
+$ If File .Eqs. " " Then Goto Endl
+$ AFile = ""
+$Loop3:
+$ OFile = AFile
+$ AFile = F$Search(File)
+$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$ Goto Loop3
+$NextEL:
+$ El = El + 1
+$ Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
diff --git a/contrib/pngminus/png2pnm.bat b/contrib/pngminus/png2pnm.bat
new file mode 100644
index 0000000..449cf36
--- /dev/null
+++ b/contrib/pngminus/png2pnm.bat
@@ -0,0 +1,41 @@
+REM -- grayscale
+png2pnm.exe -noraw ..\pngsuite\basn0g01.png basn0g01.pgm
+png2pnm.exe -noraw ..\pngsuite\basn0g02.png basn0g02.pgm
+png2pnm.exe -noraw ..\pngsuite\basn0g04.png basn0g04.pgm
+png2pnm.exe -noraw ..\pngsuite\basn0g08.png basn0g08.pgm
+png2pnm.exe -noraw ..\pngsuite\basn0g16.png basn0g16.pgm
+REM -- full-color
+png2pnm.exe -noraw ..\pngsuite\basn2c08.png basn2c08.ppm
+png2pnm.exe -noraw ..\pngsuite\basn2c16.png basn2c16.ppm
+REM -- palletted
+png2pnm.exe -noraw ..\pngsuite\basn3p01.png basn3p01.ppm
+png2pnm.exe -noraw ..\pngsuite\basn3p02.png basn3p02.ppm
+png2pnm.exe -noraw ..\pngsuite\basn3p04.png basn3p04.ppm
+png2pnm.exe -noraw ..\pngsuite\basn3p08.png basn3p08.ppm
+REM -- gray with alpha-channel
+png2pnm.exe -noraw ..\pngsuite\basn4a08.png basn4a08.pgm
+png2pnm.exe -noraw ..\pngsuite\basn4a16.png basn4a16.pgm
+REM -- color with alpha-channel
+png2pnm.exe -noraw -alpha basn6a08.pgm ..\pngsuite\basn6a08.png basn6a08.ppm
+png2pnm.exe -noraw -alpha basn6a16.pgm ..\pngsuite\basn6a16.png basn6a16.ppm
+REM -- grayscale
+png2pnm.exe -raw ..\pngsuite\basn0g01.png rawn0g01.pgm
+png2pnm.exe -raw ..\pngsuite\basn0g02.png rawn0g02.pgm
+png2pnm.exe -raw ..\pngsuite\basn0g04.png rawn0g04.pgm
+png2pnm.exe -raw ..\pngsuite\basn0g08.png rawn0g08.pgm
+png2pnm.exe -raw ..\pngsuite\basn0g16.png rawn0g16.pgm
+REM -- full-color
+png2pnm.exe -raw ..\pngsuite\basn2c08.png rawn2c08.ppm
+png2pnm.exe -raw ..\pngsuite\basn2c16.png rawn2c16.ppm
+REM -- palletted
+png2pnm.exe -raw ..\pngsuite\basn3p01.png rawn3p01.ppm
+png2pnm.exe -raw ..\pngsuite\basn3p02.png rawn3p02.ppm
+png2pnm.exe -raw ..\pngsuite\basn3p04.png rawn3p04.ppm
+png2pnm.exe -raw ..\pngsuite\basn3p08.png rawn3p08.ppm
+REM -- gray with alpha-channel
+png2pnm.exe -raw ..\pngsuite\basn4a08.png rawn4a08.pgm
+png2pnm.exe -raw ..\pngsuite\basn4a16.png rawn4a16.pgm
+REM -- color with alpha-channel
+png2pnm.exe -noraw -alpha rawn6a08.pgm ..\pngsuite\basn6a08.png rawn6a08.ppm
+png2pnm.exe -noraw -alpha rawn6a16.pgm ..\pngsuite\basn6a16.png rawn6a16.ppm
+
diff --git a/contrib/pngminus/png2pnm.c b/contrib/pngminus/png2pnm.c
new file mode 100644
index 0000000..010870a
--- /dev/null
+++ b/contrib/pngminus/png2pnm.c
@@ -0,0 +1,430 @@
+/*
+ * png2pnm.c --- conversion from PNG-file to PGM/PPM-file
+ * copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
+ *
+ * version 1.0 - 1999.10.15 - First version.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation. This software is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __TURBOC__
+#include <mem.h>
+#include <fcntl.h>
+#endif
+
+#ifndef BOOL
+#define BOOL unsigned char
+#endif
+#ifndef TRUE
+#define TRUE (BOOL) 1
+#endif
+#ifndef FALSE
+#define FALSE (BOOL) 0
+#endif
+
+#ifdef __TURBOC__
+#define STDIN 0
+#define STDOUT 1
+#define STDERR 2
+#endif
+
+/* to make png2pnm verbose so we can find problems (needs to be before png.h) */
+#ifndef PNG_DEBUG
+#define PNG_DEBUG 0
+#endif
+
+#include "png.h"
+
+/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
+#ifndef png_jmpbuf
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+/* function prototypes */
+
+int main (int argc, char *argv[]);
+void usage ();
+BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha);
+
+/*
+ * main
+ */
+
+int main(int argc, char *argv[])
+{
+ FILE *fp_rd = stdin;
+ FILE *fp_wr = stdout;
+ FILE *fp_al = NULL;
+ BOOL raw = TRUE;
+ BOOL alpha = FALSE;
+ int argi;
+
+ for (argi = 1; argi < argc; argi++)
+ {
+ if (argv[argi][0] == '-')
+ {
+ switch (argv[argi][1])
+ {
+ case 'n':
+ raw = FALSE;
+ break;
+ case 'r':
+ raw = TRUE;
+ break;
+ case 'a':
+ alpha = TRUE;
+ argi++;
+ if ((fp_al = fopen (argv[argi], "wb")) == NULL)
+ {
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, "Error: can not create alpha-channel file %s\n", argv[argi]);
+ exit (1);
+ }
+ break;
+ case 'h':
+ case '?':
+ usage();
+ exit(0);
+ break;
+ default:
+ fprintf (stderr, "PNG2PNM\n");
+ fprintf (stderr, "Error: unknown option %s\n", argv[argi]);
+ usage();
+ exit(1);
+ break;
+ } /* end switch */
+ }
+ else if (fp_rd == stdin)
+ {
+ if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
+ {
+ fprintf (stderr, "PNG2PNM\n");
+ fprintf (stderr, "Error: file %s does not exist\n", argv[argi]);
+ exit (1);
+ }
+ }
+ else if (fp_wr == stdout)
+ {
+ if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
+ {
+ fprintf (stderr, "PNG2PNM\n");
+ fprintf (stderr, "Error: can not create file %s\n", argv[argi]);
+ exit (1);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "PNG2PNM\n");
+ fprintf (stderr, "Error: too many parameters\n");
+ usage();
+ exit(1);
+ }
+ } /* end for */
+
+#ifdef __TURBOC__
+ /* set stdin/stdout if required to binary */
+ if (fp_rd == stdin)
+ {
+ setmode (STDIN, O_BINARY);
+ }
+ if ((raw) && (fp_wr == stdout))
+ {
+ setmode (STDOUT, O_BINARY);
+ }
+#endif
+
+ /* call the conversion program itself */
+ if (png2pnm (fp_rd, fp_wr, fp_al, raw, alpha) == FALSE)
+ {
+ fprintf (stderr, "PNG2PNM\n");
+ fprintf (stderr, "Error: unsuccessful convertion of PNG-image\n");
+ exit(1);
+ }
+
+ /* close input file */
+ fclose (fp_rd);
+ /* close output file */
+ fclose (fp_wr);
+ /* close alpha file */
+ if (alpha)
+ fclose (fp_al);
+
+ return 0;
+}
+
+/*
+ * usage
+ */
+
+void usage()
+{
+ fprintf (stderr, "PNG2PNM\n");
+ fprintf (stderr, " by Willem van Schaik, 1999\n");
+#ifdef __TURBOC__
+ fprintf (stderr, " for Turbo-C and Borland-C compilers\n");
+#else
+ fprintf (stderr, " for Linux (and Unix) compilers\n");
+#endif
+ fprintf (stderr, "Usage: png2pnm [options] <file>.png [<file>.pnm]\n");
+ fprintf (stderr, " or: ... | png2pnm [options]\n");
+ fprintf (stderr, "Options:\n");
+ fprintf (stderr, " -r[aw] write pnm-file in binary format (P4/P5/P6) (default)\n");
+ fprintf (stderr, " -n[oraw] write pnm-file in ascii format (P1/P2/P3)\n");
+ fprintf (stderr, " -a[lpha] <file>.pgm write PNG alpha channel as pgm-file\n");
+ fprintf (stderr, " -h | -? print this help-information\n");
+}
+
+/*
+ * png2pnm
+ */
+
+BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha)
+{
+ png_struct *png_ptr = NULL;
+ png_info *info_ptr = NULL;
+ png_byte buf[8];
+ png_byte *png_pixels = NULL;
+ png_byte **row_pointers = NULL;
+ png_byte *pix_ptr = NULL;
+ png_uint_32 row_bytes;
+
+ png_uint_32 width;
+ png_uint_32 height;
+ int bit_depth;
+ int channels;
+ int color_type;
+ int alpha_present;
+ int row, col;
+ int ret;
+ int i;
+ long dep_16;
+
+ /* read and check signature in PNG file */
+ ret = fread (buf, 1, 8, png_file);
+ if (ret != 8)
+ return FALSE;
+
+ ret = png_check_sig (buf, 8);
+ if (!ret)
+ return FALSE;
+
+ /* create png and info structures */
+
+ png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+ if (!png_ptr)
+ return FALSE; /* out of memory */
+
+ info_ptr = png_create_info_struct (png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct (&png_ptr, NULL, NULL);
+ return FALSE; /* out of memory */
+ }
+
+ if (setjmp (png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+ return FALSE;
+ }
+
+ /* set up the input control for C streams */
+ png_init_io (png_ptr, png_file);
+ png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */
+
+ /* read the file information */
+ png_read_info (png_ptr, info_ptr);
+
+ /* get size and bit-depth of the PNG-image */
+ png_get_IHDR (png_ptr, info_ptr,
+ &width, &height, &bit_depth, &color_type,
+ NULL, NULL, NULL);
+
+ /* set-up the transformations */
+
+ /* transform paletted images into full-color rgb */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand (png_ptr);
+ /* expand images to bit-depth 8 (only applicable for grayscale images) */
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand (png_ptr);
+ /* transform transparency maps into full alpha-channel */
+ if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand (png_ptr);
+
+#ifdef NJET
+ /* downgrade 16-bit images to 8 bit */
+ if (bit_depth == 16)
+ png_set_strip_16 (png_ptr);
+ /* transform grayscale images into full-color */
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb (png_ptr);
+ /* only if file has a file gamma, we do a correction */
+ if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
+ png_set_gamma (png_ptr, (double) 2.2, file_gamma);
+#endif
+
+ /* all transformations have been registered; now update info_ptr data,
+ * get rowbytes and channels, and allocate image memory */
+
+ png_read_update_info (png_ptr, info_ptr);
+
+ /* get the new color-type and bit-depth (after expansion/stripping) */
+ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ NULL, NULL, NULL);
+
+ /* check for 16-bit files */
+ if (bit_depth == 16)
+ {
+ raw = FALSE;
+#ifdef __TURBOC__
+ pnm_file->flags &= ~((unsigned) _F_BIN);
+#endif
+ }
+
+ /* calculate new number of channels and store alpha-presence */
+ if (color_type == PNG_COLOR_TYPE_GRAY)
+ channels = 1;
+ else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ channels = 2;
+ else if (color_type == PNG_COLOR_TYPE_RGB)
+ channels = 3;
+ else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ channels = 4;
+ else
+ channels = 0; /* should never happen */
+ alpha_present = (channels - 1) % 2;
+
+ /* check if alpha is expected to be present in file */
+ if (alpha && !alpha_present)
+ {
+ fprintf (stderr, "PNG2PNM\n");
+ fprintf (stderr, "Error: PNG-file doesn't contain alpha channel\n");
+ exit (1);
+ }
+
+ /* row_bytes is the width x number of channels x (bit-depth / 8) */
+ row_bytes = png_get_rowbytes (png_ptr, info_ptr);
+
+ if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) {
+ png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+ return FALSE;
+ }
+
+ if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL)
+ {
+ png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+ free (png_pixels);
+ png_pixels = NULL;
+ return FALSE;
+ }
+
+ /* set the individual row_pointers to point at the correct offsets */
+ for (i = 0; i < (height); i++)
+ row_pointers[i] = png_pixels + i * row_bytes;
+
+ /* now we can go ahead and just read the whole image */
+ png_read_image (png_ptr, row_pointers);
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end (png_ptr, info_ptr);
+
+ /* clean up after the read, and free any memory allocated - REQUIRED */
+ png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL);
+
+ /* write header of PNM file */
+
+ if ((color_type == PNG_COLOR_TYPE_GRAY) ||
+ (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
+ {
+ fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2");
+ fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
+ fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
+ }
+ else if ((color_type == PNG_COLOR_TYPE_RGB) ||
+ (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
+ {
+ fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3");
+ fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
+ fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
+ }
+
+ /* write header of PGM file with alpha channel */
+
+ if ((alpha) &&
+ ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
+ (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
+ {
+ fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2");
+ fprintf (alpha_file, "%d %d\n", (int) width, (int) height);
+ fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
+ }
+
+ /* write data to PNM file */
+ pix_ptr = png_pixels;
+
+ for (row = 0; row < height; row++)
+ {
+ for (col = 0; col < width; col++)
+ {
+ for (i = 0; i < (channels - alpha_present); i++)
+ {
+ if (raw)
+ fputc ((int) *pix_ptr++ , pnm_file);
+ else
+ if (bit_depth == 16){
+ dep_16 = (long) *pix_ptr++;
+ fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
+ }
+ else
+ fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
+ }
+ if (alpha_present)
+ {
+ if (!alpha)
+ {
+ pix_ptr++; /* alpha */
+ if (bit_depth == 16)
+ pix_ptr++;
+ }
+ else /* output alpha-channel as pgm file */
+ {
+ if (raw)
+ fputc ((int) *pix_ptr++ , alpha_file);
+ else
+ if (bit_depth == 16){
+ dep_16 = (long) *pix_ptr++;
+ fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
+ }
+ else
+ fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
+ }
+ } /* if alpha_present */
+
+ if (!raw)
+ if (col % 4 == 3)
+ fprintf (pnm_file, "\n");
+ } /* end for col */
+
+ if (!raw)
+ if (col % 4 != 0)
+ fprintf (pnm_file, "\n");
+ } /* end for row */
+
+ if (row_pointers != (unsigned char**) NULL)
+ free (row_pointers);
+ if (png_pixels != (unsigned char*) NULL)
+ free (png_pixels);
+
+ return TRUE;
+
+} /* end of source */
+
diff --git a/contrib/pngminus/png2pnm.sh b/contrib/pngminus/png2pnm.sh
new file mode 100644
index 0000000..b1c0537
--- /dev/null
+++ b/contrib/pngminus/png2pnm.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# -- grayscale
+./png2pnm -noraw ../pngsuite/basn0g01.png basn0g01.pgm
+./png2pnm -noraw ../pngsuite/basn0g02.png basn0g02.pgm
+./png2pnm -noraw ../pngsuite/basn0g04.png basn0g04.pgm
+./png2pnm -noraw ../pngsuite/basn0g08.png basn0g08.pgm
+./png2pnm -noraw ../pngsuite/basn0g16.png basn0g16.pgm
+# -- full-color
+./png2pnm -noraw ../pngsuite/basn2c08.png basn2c08.ppm
+./png2pnm -noraw ../pngsuite/basn2c16.png basn2c16.ppm
+# -- palletted
+./png2pnm -noraw ../pngsuite/basn3p01.png basn3p01.ppm
+./png2pnm -noraw ../pngsuite/basn3p02.png basn3p02.ppm
+./png2pnm -noraw ../pngsuite/basn3p04.png basn3p04.ppm
+./png2pnm -noraw ../pngsuite/basn3p08.png basn3p08.ppm
+# -- gray with alpha-channel
+./png2pnm -noraw ../pngsuite/basn4a08.png basn4a08.pgm
+./png2pnm -noraw ../pngsuite/basn4a16.png basn4a16.pgm
+# -- color with alpha-channel
+./png2pnm -noraw -alpha basn6a08.pgm ../pngsuite/basn6a08.png basn6a08.ppm
+./png2pnm -noraw -alpha basn6a16.pgm ../pngsuite/basn6a16.png basn6a16.ppm
+# -- grayscale
+./png2pnm -raw ../pngsuite/basn0g01.png rawn0g01.pgm
+./png2pnm -raw ../pngsuite/basn0g02.png rawn0g02.pgm
+./png2pnm -raw ../pngsuite/basn0g04.png rawn0g04.pgm
+./png2pnm -raw ../pngsuite/basn0g08.png rawn0g08.pgm
+./png2pnm -raw ../pngsuite/basn0g16.png rawn0g16.pgm
+# -- full-color
+./png2pnm -raw ../pngsuite/basn2c08.png rawn2c08.ppm
+./png2pnm -raw ../pngsuite/basn2c16.png rawn2c16.ppm
+# -- palletted
+./png2pnm -raw ../pngsuite/basn3p01.png rawn3p01.ppm
+./png2pnm -raw ../pngsuite/basn3p02.png rawn3p02.ppm
+./png2pnm -raw ../pngsuite/basn3p04.png rawn3p04.ppm
+./png2pnm -raw ../pngsuite/basn3p08.png rawn3p08.ppm
+# -- gray with alpha-channel
+./png2pnm -raw ../pngsuite/basn4a08.png rawn4a08.pgm
+./png2pnm -raw ../pngsuite/basn4a16.png rawn4a16.pgm
+# -- color with alpha-channel
+./png2pnm -noraw -alpha rawn6a08.pgm ../pngsuite/basn6a08.png rawn6a08.ppm
+./png2pnm -noraw -alpha rawn6a16.pgm ../pngsuite/basn6a16.png rawn6a16.ppm
+
diff --git a/contrib/pngminus/pngminus.bat b/contrib/pngminus/pngminus.bat
new file mode 100644
index 0000000..911bb8d
--- /dev/null
+++ b/contrib/pngminus/pngminus.bat
@@ -0,0 +1,4 @@
+make -f makefile.tc3
+call png2pnm.bat
+call pnm2png.bat
+
diff --git a/contrib/pngminus/pngminus.sh b/contrib/pngminus/pngminus.sh
new file mode 100644
index 0000000..2a0a9d8
--- /dev/null
+++ b/contrib/pngminus/pngminus.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+make -f makefile.std
+sh png2pnm.sh
+sh pnm2png.sh
+
diff --git a/contrib/pngminus/pnm2png.bat b/contrib/pngminus/pnm2png.bat
new file mode 100644
index 0000000..f756cb8
--- /dev/null
+++ b/contrib/pngminus/pnm2png.bat
@@ -0,0 +1,41 @@
+REM -- grayscale
+pnm2png.exe basn0g01.pgm basn0g01.png
+pnm2png.exe basn0g02.pgm basn0g02.png
+pnm2png.exe basn0g04.pgm basn0g04.png
+pnm2png.exe basn0g08.pgm basn0g08.png
+pnm2png.exe basn0g16.pgm basn0g16.png
+REM -- full-color
+pnm2png.exe basn2c08.ppm basn2c08.png
+pnm2png.exe basn2c16.ppm basn2c16.png
+REM -- palletted
+pnm2png.exe basn3p01.ppm basn3p01.png
+pnm2png.exe basn3p02.ppm basn3p02.png
+pnm2png.exe basn3p04.ppm basn3p04.png
+pnm2png.exe basn3p08.ppm basn3p08.png
+REM -- gray with alpha-channel
+pnm2png.exe -alpha basn6a08.pgm basn4a08.pgm basn4a08.png
+pnm2png.exe -alpha basn6a16.pgm basn4a16.pgm basn4a16.png
+REM -- color with alpha-channel
+pnm2png.exe -alpha basn6a08.pgm basn6a08.ppm basn6a08.png
+pnm2png.exe -alpha basn6a16.pgm basn6a16.ppm basn6a16.png
+REM -- grayscale
+pnm2png.exe rawn0g01.pgm rawn0g01.png
+pnm2png.exe rawn0g02.pgm rawn0g02.png
+pnm2png.exe rawn0g04.pgm rawn0g04.png
+pnm2png.exe rawn0g08.pgm rawn0g08.png
+pnm2png.exe rawn0g16.pgm rawn0g16.png
+REM -- full-color
+pnm2png.exe rawn2c08.ppm rawn2c08.png
+pnm2png.exe rawn2c16.ppm rawn2c16.png
+REM -- palletted
+pnm2png.exe rawn3p01.ppm rawn3p01.png
+pnm2png.exe rawn3p02.ppm rawn3p02.png
+pnm2png.exe rawn3p04.ppm rawn3p04.png
+pnm2png.exe rawn3p08.ppm rawn3p08.png
+REM -- gray with alpha-channel
+pnm2png.exe -alpha rawn6a08.pgm rawn4a08.pgm rawn4a08.png
+pnm2png.exe -alpha rawn6a16.pgm rawn4a16.pgm rawn4a16.png
+REM -- color with alpha-channel
+pnm2png.exe -alpha rawn6a08.pgm rawn6a08.ppm rawn6a08.png
+pnm2png.exe -alpha rawn6a16.pgm rawn6a16.ppm rawn6a16.png
+
diff --git a/contrib/pngminus/pnm2png.c b/contrib/pngminus/pnm2png.c
new file mode 100644
index 0000000..4cdfad8
--- /dev/null
+++ b/contrib/pngminus/pnm2png.c
@@ -0,0 +1,533 @@
+/*
+ * pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file
+ * copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
+ *
+ * version 1.0 - 1999.10.15 - First version.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation. This software is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __TURBOC__
+#include <mem.h>
+#include <fcntl.h>
+#endif
+
+#ifndef BOOL
+#define BOOL unsigned char
+#endif
+#ifndef TRUE
+#define TRUE (BOOL) 1
+#endif
+#ifndef FALSE
+#define FALSE (BOOL) 0
+#endif
+
+#define STDIN 0
+#define STDOUT 1
+#define STDERR 2
+
+/* to make pnm2png verbose so we can find problems (needs to be before png.h) */
+#ifndef PNG_DEBUG
+#define PNG_DEBUG 0
+#endif
+
+#include "png.h"
+
+/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
+#ifndef png_jmpbuf
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+/* function prototypes */
+
+int main (int argc, char *argv[]);
+void usage ();
+BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha);
+void get_token(FILE *pnm_file, char *token);
+png_uint_32 get_data (FILE *pnm_file, int depth);
+png_uint_32 get_value (FILE *pnm_file, int depth);
+
+/*
+ * main
+ */
+
+int main(int argc, char *argv[])
+{
+ FILE *fp_rd = stdin;
+ FILE *fp_al = NULL;
+ FILE *fp_wr = stdout;
+ BOOL interlace = FALSE;
+ BOOL alpha = FALSE;
+ int argi;
+
+ for (argi = 1; argi < argc; argi++)
+ {
+ if (argv[argi][0] == '-')
+ {
+ switch (argv[argi][1])
+ {
+ case 'i':
+ interlace = TRUE;
+ break;
+ case 'a':
+ alpha = TRUE;
+ argi++;
+ if ((fp_al = fopen (argv[argi], "rb")) == NULL)
+ {
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, "Error: alpha-channel file %s does not exist\n",
+ argv[argi]);
+ exit (1);
+ }
+ break;
+ case 'h':
+ case '?':
+ usage();
+ exit(0);
+ break;
+ default:
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, "Error: unknown option %s\n", argv[argi]);
+ usage();
+ exit(1);
+ break;
+ } /* end switch */
+ }
+ else if (fp_rd == stdin)
+ {
+ if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
+ {
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, "Error: file %s does not exist\n", argv[argi]);
+ exit (1);
+ }
+ }
+ else if (fp_wr == stdout)
+ {
+ if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
+ {
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, "Error: can not create PNG-file %s\n", argv[argi]);
+ exit (1);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, "Error: too many parameters\n");
+ usage();
+ exit (1);
+ }
+ } /* end for */
+
+#ifdef __TURBOC__
+ /* set stdin/stdout to binary, we're reading the PNM always! in binary format */
+ if (fp_rd == stdin)
+ {
+ setmode (STDIN, O_BINARY);
+ }
+ if (fp_wr == stdout)
+ {
+ setmode (STDOUT, O_BINARY);
+ }
+#endif
+
+ /* call the conversion program itself */
+ if (pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha) == FALSE)
+ {
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, "Error: unsuccessful converting to PNG-image\n");
+ exit (1);
+ }
+
+ /* close input file */
+ fclose (fp_rd);
+ /* close output file */
+ fclose (fp_wr);
+ /* close alpha file */
+ if (alpha)
+ fclose (fp_al);
+
+ return 0;
+}
+
+/*
+ * usage
+ */
+
+void usage()
+{
+ fprintf (stderr, "PNM2PNG\n");
+ fprintf (stderr, " by Willem van Schaik, 1999\n");
+#ifdef __TURBOC__
+ fprintf (stderr, " for Turbo-C and Borland-C compilers\n");
+#else
+ fprintf (stderr, " for Linux (and Unix) compilers\n");
+#endif
+ fprintf (stderr, "Usage: pnm2png [options] <file>.<pnm> [<file>.png]\n");
+ fprintf (stderr, " or: ... | pnm2png [options]\n");
+ fprintf (stderr, "Options:\n");
+ fprintf (stderr, " -i[nterlace] write png-file with interlacing on\n");
+ fprintf (stderr, " -a[lpha] <file>.pgm read PNG alpha channel as pgm-file\n");
+ fprintf (stderr, " -h | -? print this help-information\n");
+}
+
+/*
+ * pnm2png
+ */
+
+BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha)
+{
+ png_struct *png_ptr = NULL;
+ png_info *info_ptr = NULL;
+ png_byte *png_pixels = NULL;
+ png_byte **row_pointers = NULL;
+ png_byte *pix_ptr = NULL;
+ png_uint_32 row_bytes;
+
+ char type_token[16];
+ char width_token[16];
+ char height_token[16];
+ char maxval_token[16];
+ int color_type;
+ png_uint_32 width, alpha_width;
+ png_uint_32 height, alpha_height;
+ png_uint_32 maxval;
+ int bit_depth = 0;
+ int channels;
+ int alpha_depth = 0;
+ int alpha_present;
+ int row, col;
+ BOOL raw, alpha_raw = FALSE;
+ png_uint_32 tmp16;
+ int i;
+
+ /* read header of PNM file */
+
+ get_token(pnm_file, type_token);
+ if (type_token[0] != 'P')
+ {
+ return FALSE;
+ }
+ else if ((type_token[1] == '1') || (type_token[1] == '4'))
+ {
+ raw = (type_token[1] == '4');
+ color_type = PNG_COLOR_TYPE_GRAY;
+ bit_depth = 1;
+ }
+ else if ((type_token[1] == '2') || (type_token[1] == '5'))
+ {
+ raw = (type_token[1] == '5');
+ color_type = PNG_COLOR_TYPE_GRAY;
+ get_token(pnm_file, width_token);
+ sscanf (width_token, "%lu", &width);
+ get_token(pnm_file, height_token);
+ sscanf (height_token, "%lu", &height);
+ get_token(pnm_file, maxval_token);
+ sscanf (maxval_token, "%lu", &maxval);
+ if (maxval <= 1)
+ bit_depth = 1;
+ else if (maxval <= 3)
+ bit_depth = 2;
+ else if (maxval <= 15)
+ bit_depth = 4;
+ else if (maxval <= 255)
+ bit_depth = 8;
+ else /* if (maxval <= 65535) */
+ bit_depth = 16;
+ }
+ else if ((type_token[1] == '3') || (type_token[1] == '6'))
+ {
+ raw = (type_token[1] == '6');
+ color_type = PNG_COLOR_TYPE_RGB;
+ get_token(pnm_file, width_token);
+ sscanf (width_token, "%lu", &width);
+ get_token(pnm_file, height_token);
+ sscanf (height_token, "%lu", &height);
+ get_token(pnm_file, maxval_token);
+ sscanf (maxval_token, "%lu", &maxval);
+ if (maxval <= 1)
+ bit_depth = 1;
+ else if (maxval <= 3)
+ bit_depth = 2;
+ else if (maxval <= 15)
+ bit_depth = 4;
+ else if (maxval <= 255)
+ bit_depth = 8;
+ else /* if (maxval <= 65535) */
+ bit_depth = 16;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ /* read header of PGM file with alpha channel */
+
+ if (alpha)
+ {
+ if (color_type == PNG_COLOR_TYPE_GRAY)
+ color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ if (color_type == PNG_COLOR_TYPE_RGB)
+ color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+
+ get_token(alpha_file, type_token);
+ if (type_token[0] != 'P')
+ {
+ return FALSE;
+ }
+ else if ((type_token[1] == '2') || (type_token[1] == '5'))
+ {
+ alpha_raw = (type_token[1] == '5');
+ get_token(alpha_file, width_token);
+ sscanf (width_token, "%lu", &alpha_width);
+ if (alpha_width != width)
+ return FALSE;
+ get_token(alpha_file, height_token);
+ sscanf (height_token, "%lu", &alpha_height);
+ if (alpha_height != height)
+ return FALSE;
+ get_token(alpha_file, maxval_token);
+ sscanf (maxval_token, "%lu", &maxval);
+ if (maxval <= 1)
+ alpha_depth = 1;
+ else if (maxval <= 3)
+ alpha_depth = 2;
+ else if (maxval <= 15)
+ alpha_depth = 4;
+ else if (maxval <= 255)
+ alpha_depth = 8;
+ else /* if (maxval <= 65535) */
+ alpha_depth = 16;
+ if (alpha_depth != bit_depth)
+ return FALSE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ } /* end if alpha */
+
+ /* calculate the number of channels and store alpha-presence */
+ if (color_type == PNG_COLOR_TYPE_GRAY)
+ channels = 1;
+ else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ channels = 2;
+ else if (color_type == PNG_COLOR_TYPE_RGB)
+ channels = 3;
+ else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ channels = 4;
+ else
+ channels = 0; /* should not happen */
+
+ alpha_present = (channels - 1) % 2;
+
+ /* row_bytes is the width x number of channels x (bit-depth / 8) */
+ row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
+
+ if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL)
+ return FALSE;
+
+ /* read data from PNM file */
+ pix_ptr = png_pixels;
+
+ for (row = 0; row < height; row++)
+ {
+ for (col = 0; col < width; col++)
+ {
+ for (i = 0; i < (channels - alpha_present); i++)
+ {
+ if (raw)
+ *pix_ptr++ = get_data (pnm_file, bit_depth);
+ else
+ if (bit_depth <= 8)
+ *pix_ptr++ = get_value (pnm_file, bit_depth);
+ else
+ {
+ tmp16 = get_value (pnm_file, bit_depth);
+ *pix_ptr = (png_byte) ((tmp16 >> 8) & 0xFF);
+ pix_ptr++;
+ *pix_ptr = (png_byte) (tmp16 & 0xFF);
+ pix_ptr++;
+ }
+ }
+
+ if (alpha) /* read alpha-channel from pgm file */
+ {
+ if (alpha_raw)
+ *pix_ptr++ = get_data (alpha_file, alpha_depth);
+ else
+ if (alpha_depth <= 8)
+ *pix_ptr++ = get_value (alpha_file, bit_depth);
+ else
+ {
+ tmp16 = get_value (alpha_file, bit_depth);
+ *pix_ptr++ = (png_byte) ((tmp16 >> 8) & 0xFF);
+ *pix_ptr++ = (png_byte) (tmp16 & 0xFF);
+ }
+ } /* if alpha */
+
+ } /* end for col */
+ } /* end for row */
+
+ /* prepare the standard PNG structures */
+ png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ return FALSE;
+ }
+ info_ptr = png_create_info_struct (png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ return FALSE;
+ }
+
+ /* setjmp() must be called in every function that calls a PNG-reading libpng function */
+ if (setjmp (png_jmpbuf(png_ptr)))
+ {
+ png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ return FALSE;
+ }
+
+ /* initialize the png structure */
+ png_init_io (png_ptr, png_file);
+
+ /* we're going to write more or less the same PNG as the input file */
+ png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type,
+ (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ /* write the file header information */
+ png_write_info (png_ptr, info_ptr);
+
+ /* if needed we will allocate memory for an new array of row-pointers */
+ if (row_pointers == (unsigned char**) NULL)
+ {
+ if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL)
+ {
+ png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ return FALSE;
+ }
+ }
+
+ /* set the individual row_pointers to point at the correct offsets */
+ for (i = 0; i < (height); i++)
+ row_pointers[i] = png_pixels + i * row_bytes;
+
+ /* write out the entire image data in one call */
+ png_write_image (png_ptr, row_pointers);
+
+ /* write the additional chuncks to the PNG file (not really needed) */
+ png_write_end (png_ptr, info_ptr);
+
+ /* clean up after the write, and free any memory allocated */
+ png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+
+ if (row_pointers != (unsigned char**) NULL)
+ free (row_pointers);
+ if (png_pixels != (unsigned char*) NULL)
+ free (png_pixels);
+
+ return TRUE;
+} /* end of pnm2png */
+
+/*
+ * get_token() - gets the first string after whitespace
+ */
+
+void get_token(FILE *pnm_file, char *token)
+{
+ int i = 0;
+
+ /* remove white-space */
+ do
+ {
+ token[i] = (unsigned char) fgetc (pnm_file);
+ }
+ while ((token[i] == '\n') || (token[i] == '\r') || (token[i] == ' '));
+
+ /* read string */
+ do
+ {
+ i++;
+ token[i] = (unsigned char) fgetc (pnm_file);
+ }
+ while ((token[i] != '\n') && (token[i] != '\r') && (token[i] != ' '));
+
+ token[i] = '\0';
+
+ return;
+}
+
+/*
+ * get_data() - takes first byte and converts into next pixel value,
+ * taking as much bits as defined by bit-depth and
+ * using the bit-depth to fill up a byte (0Ah -> AAh)
+ */
+
+png_uint_32 get_data (FILE *pnm_file, int depth)
+{
+ static int bits_left = 0;
+ static int old_value = 0;
+ static int mask = 0;
+ int i;
+ png_uint_32 ret_value;
+
+ if (mask == 0)
+ for (i = 0; i < depth; i++)
+ mask = (mask >> 1) | 0x80;
+
+ if (bits_left <= 0)
+ {
+ old_value = fgetc (pnm_file);
+ bits_left = 8;
+ }
+
+ ret_value = old_value & mask;
+ for (i = 1; i < (8 / depth); i++)
+ ret_value = ret_value || (ret_value >> depth);
+
+ old_value = (old_value << depth) & 0xFF;
+ bits_left -= depth;
+
+ return ret_value;
+}
+
+/*
+ * get_value() - takes first (numeric) string and converts into number,
+ * using the bit-depth to fill up a byte (0Ah -> AAh)
+ */
+
+png_uint_32 get_value (FILE *pnm_file, int depth)
+{
+ static png_uint_32 mask = 0;
+ png_byte token[16];
+ png_uint_32 ret_value;
+ int i = 0;
+
+ if (mask == 0)
+ for (i = 0; i < depth; i++)
+ mask = (mask << 1) | 0x01;
+
+ get_token (pnm_file, (char *) token);
+ sscanf ((const char *) token, "%lu", &ret_value);
+
+ ret_value &= mask;
+
+ if (depth < 8)
+ for (i = 0; i < (8 / depth); i++)
+ ret_value = (ret_value << depth) || ret_value;
+
+ return ret_value;
+}
+
+/* end of source */
+
diff --git a/contrib/pngminus/pnm2png.sh b/contrib/pngminus/pnm2png.sh
new file mode 100644
index 0000000..d79df2f
--- /dev/null
+++ b/contrib/pngminus/pnm2png.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# -- grayscale
+./pnm2png basn0g01.pgm basn0g01.png
+./pnm2png basn0g02.pgm basn0g02.png
+./pnm2png basn0g04.pgm basn0g04.png
+./pnm2png basn0g08.pgm basn0g08.png
+./pnm2png basn0g16.pgm basn0g16.png
+# -- full-color
+./pnm2png basn2c08.ppm basn2c08.png
+./pnm2png basn2c16.ppm basn2c16.png
+# -- palletted
+./pnm2png basn3p01.ppm basn3p01.png
+./pnm2png basn3p02.ppm basn3p02.png
+./pnm2png basn3p04.ppm basn3p04.png
+./pnm2png basn3p08.ppm basn3p08.png
+# -- gray with alpha-channel
+./pnm2png -alpha basn6a08.pgm basn4a08.pgm basn4a08.png
+./pnm2png -alpha basn6a16.pgm basn4a16.pgm basn4a16.png
+# -- color with alpha-channel
+./pnm2png -alpha basn6a08.pgm basn6a08.ppm basn6a08.png
+./pnm2png -alpha basn6a16.pgm basn6a16.ppm basn6a16.png
+# -- grayscale
+./pnm2png rawn0g01.pgm rawn0g01.png
+./pnm2png rawn0g02.pgm rawn0g02.png
+./pnm2png rawn0g04.pgm rawn0g04.png
+./pnm2png rawn0g08.pgm rawn0g08.png
+./pnm2png rawn0g16.pgm rawn0g16.png
+# -- full-color
+./pnm2png rawn2c08.ppm rawn2c08.png
+./pnm2png rawn2c16.ppm rawn2c16.png
+# -- palletted
+./pnm2png rawn3p01.ppm rawn3p01.png
+./pnm2png rawn3p02.ppm rawn3p02.png
+./pnm2png rawn3p04.ppm rawn3p04.png
+./pnm2png rawn3p08.ppm rawn3p08.png
+# -- gray with alpha-channel
+./pnm2png -alpha rawn6a08.pgm rawn4a08.pgm rawn4a08.png
+./pnm2png -alpha rawn6a16.pgm rawn4a16.pgm rawn4a16.png
+# -- color with alpha-channel
+./pnm2png -alpha rawn6a08.pgm rawn6a08.ppm rawn6a08.png
+./pnm2png -alpha rawn6a16.pgm rawn6a16.ppm rawn6a16.png
+
diff --git a/contrib/pngsuite/README b/contrib/pngsuite/README
new file mode 100644
index 0000000..714d12c
--- /dev/null
+++ b/contrib/pngsuite/README
@@ -0,0 +1,85 @@
+
+pngsuite
+--------
+(c) Willem van Schaik, 1999
+
+Permission to use, copy, and distribute these images for any purpose and
+without fee is hereby granted.
+
+These 15 images are part of the much larger PngSuite test-set of
+images, available for developers of PNG supporting software. The
+complete set, available at http:/www.schaik.com/pngsuite/, contains
+a variety of images to test interlacing, gamma settings, ancillary
+chunks, etc.
+
+The images in this directory represent the basic PNG color-types:
+grayscale (1-16 bit deep), full color (8 or 16 bit), paletted
+(1-8 bit) and grayscale or color images with alpha channel. You
+can use them to test the proper functioning of PNG software.
+
+ filename depth type
+ ------------ ------ --------------
+ basn0g01.png 1-bit grayscale
+ basn0g02.png 2-bit grayscale
+ basn0g04.png 4-bit grayscale
+ basn0g08.png 8-bit grayscale
+ basn0g16.png 16-bit grayscale
+ basn2c08.png 8-bit truecolor
+ basn2c16.png 16-bit truecolor
+ basn3p01.png 1-bit paletted
+ basn3p02.png 2-bit paletted
+ basn3p04.png 4-bit paletted
+ basn3p08.png 8-bit paletted
+ basn4a08.png 8-bit gray with alpha
+ basn4a16.png 16-bit gray with alpha
+ basn6a08.png 8-bit RGBA
+ basn6a16.png 16-bit RGBA
+
+Here is the correct result of typing "pngtest -m *.png" in
+this directory:
+
+Testing basn0g01.png: PASS (524 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g04.png: PASS (520 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g08.png: PASS (3 zero samples)
+ Filter 1 was used 9 times
+ Filter 4 was used 23 times
+Testing basn0g16.png: PASS (1 zero samples)
+ Filter 1 was used 1 times
+ Filter 2 was used 31 times
+Testing basn2c08.png: PASS (6 zero samples)
+ Filter 1 was used 5 times
+ Filter 4 was used 27 times
+Testing basn2c16.png: PASS (592 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn3p01.png: PASS (512 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p04.png: PASS (544 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p08.png: PASS (4 zero samples)
+ Filter 0 was used 32 times
+Testing basn4a08.png: PASS (32 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn4a16.png: PASS (64 zero samples)
+ Filter 0 was used 1 times
+ Filter 1 was used 2 times
+ Filter 2 was used 1 times
+ Filter 4 was used 28 times
+Testing basn6a08.png: PASS (160 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn6a16.png: PASS (1072 zero samples)
+ Filter 1 was used 4 times
+ Filter 4 was used 28 times
+libpng passes test
+
+Willem van Schaik
+<willem@schaik.com>
+October 1999
diff --git a/contrib/pngsuite/basn0g01.png b/contrib/pngsuite/basn0g01.png
new file mode 100644
index 0000000..e31e1c7
--- /dev/null
+++ b/contrib/pngsuite/basn0g01.png
Binary files differ
diff --git a/contrib/pngsuite/basn0g02.png b/contrib/pngsuite/basn0g02.png
new file mode 100644
index 0000000..68809dd
--- /dev/null
+++ b/contrib/pngsuite/basn0g02.png
Binary files differ
diff --git a/contrib/pngsuite/basn0g04.png b/contrib/pngsuite/basn0g04.png
new file mode 100644
index 0000000..6fa089c
--- /dev/null
+++ b/contrib/pngsuite/basn0g04.png
Binary files differ
diff --git a/contrib/pngsuite/basn0g08.png b/contrib/pngsuite/basn0g08.png
new file mode 100644
index 0000000..bf522ee
--- /dev/null
+++ b/contrib/pngsuite/basn0g08.png
Binary files differ
diff --git a/contrib/pngsuite/basn0g16.png b/contrib/pngsuite/basn0g16.png
new file mode 100644
index 0000000..318ebca
--- /dev/null
+++ b/contrib/pngsuite/basn0g16.png
Binary files differ
diff --git a/contrib/pngsuite/basn2c08.png b/contrib/pngsuite/basn2c08.png
new file mode 100644
index 0000000..21d2f91
--- /dev/null
+++ b/contrib/pngsuite/basn2c08.png
Binary files differ
diff --git a/contrib/pngsuite/basn2c16.png b/contrib/pngsuite/basn2c16.png
new file mode 100644
index 0000000..1bd4a4d
--- /dev/null
+++ b/contrib/pngsuite/basn2c16.png
Binary files differ
diff --git a/contrib/pngsuite/basn3p01.png b/contrib/pngsuite/basn3p01.png
new file mode 100644
index 0000000..a21db59
--- /dev/null
+++ b/contrib/pngsuite/basn3p01.png
Binary files differ
diff --git a/contrib/pngsuite/basn3p02.png b/contrib/pngsuite/basn3p02.png
new file mode 100644
index 0000000..1d0ab61
--- /dev/null
+++ b/contrib/pngsuite/basn3p02.png
Binary files differ
diff --git a/contrib/pngsuite/basn3p04.png b/contrib/pngsuite/basn3p04.png
new file mode 100644
index 0000000..6dc6eac
--- /dev/null
+++ b/contrib/pngsuite/basn3p04.png
Binary files differ
diff --git a/contrib/pngsuite/basn3p08.png b/contrib/pngsuite/basn3p08.png
new file mode 100644
index 0000000..0e07f48
--- /dev/null
+++ b/contrib/pngsuite/basn3p08.png
Binary files differ
diff --git a/contrib/pngsuite/basn4a08.png b/contrib/pngsuite/basn4a08.png
new file mode 100644
index 0000000..3bb0dd0
--- /dev/null
+++ b/contrib/pngsuite/basn4a08.png
Binary files differ
diff --git a/contrib/pngsuite/basn4a16.png b/contrib/pngsuite/basn4a16.png
new file mode 100644
index 0000000..6dbee9f
--- /dev/null
+++ b/contrib/pngsuite/basn4a16.png
Binary files differ
diff --git a/contrib/pngsuite/basn6a08.png b/contrib/pngsuite/basn6a08.png
new file mode 100644
index 0000000..6106230
--- /dev/null
+++ b/contrib/pngsuite/basn6a08.png
Binary files differ
diff --git a/contrib/pngsuite/basn6a16.png b/contrib/pngsuite/basn6a16.png
new file mode 100644
index 0000000..a9bf3cb
--- /dev/null
+++ b/contrib/pngsuite/basn6a16.png
Binary files differ
diff --git a/contrib/visupng/PngFile.c b/contrib/visupng/PngFile.c
new file mode 100644
index 0000000..959afe9
--- /dev/null
+++ b/contrib/visupng/PngFile.c
@@ -0,0 +1,439 @@
+//-------------------------------------
+// PNGFILE.C -- Image File Functions
+//-------------------------------------
+
+// Copyright 2000, Willem van Schaik. For conditions of distribution and
+// use, see the copyright/license/disclaimer notice in png.h
+
+#include <windows.h>
+#include <commdlg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "png.h"
+#include "pngfile.h"
+#include "cexcept.h"
+
+define_exception_type(const char *);
+extern struct exception_context the_exception_context[1];
+struct exception_context the_exception_context[1];
+png_const_charp msg;
+
+static OPENFILENAME ofn;
+
+static png_structp png_ptr = NULL;
+static png_infop info_ptr = NULL;
+
+
+// cexcept interface
+
+static void
+png_cexcept_error(png_structp png_ptr, png_const_charp msg)
+{
+ if(png_ptr)
+ ;
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr, "libpng error: %s\n", msg);
+#endif
+ {
+ Throw msg;
+ }
+}
+
+// Windows open-file functions
+
+void PngFileInitialize (HWND hwnd)
+{
+ static TCHAR szFilter[] = TEXT ("PNG Files (*.PNG)\0*.png\0")
+ TEXT ("All Files (*.*)\0*.*\0\0");
+
+ ofn.lStructSize = sizeof (OPENFILENAME);
+ ofn.hwndOwner = hwnd;
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 0;
+ ofn.lpstrFile = NULL; // Set in Open and Close functions
+ ofn.nMaxFile = MAX_PATH;
+ ofn.lpstrFileTitle = NULL; // Set in Open and Close functions
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = NULL;
+ ofn.Flags = 0; // Set in Open and Close functions
+ ofn.nFileOffset = 0;
+ ofn.nFileExtension = 0;
+ ofn.lpstrDefExt = TEXT ("png");
+ ofn.lCustData = 0;
+ ofn.lpfnHook = NULL;
+ ofn.lpTemplateName = NULL;
+}
+
+BOOL PngFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
+{
+ ofn.hwndOwner = hwnd;
+ ofn.lpstrFile = pstrFileName;
+ ofn.lpstrFileTitle = pstrTitleName;
+ ofn.Flags = OFN_HIDEREADONLY;
+
+ return GetOpenFileName (&ofn);
+}
+
+BOOL PngFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
+{
+ ofn.hwndOwner = hwnd;
+ ofn.lpstrFile = pstrFileName;
+ ofn.lpstrFileTitle = pstrTitleName;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
+
+ return GetSaveFileName (&ofn);
+}
+
+// PNG image handler functions
+
+BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData,
+ int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor)
+{
+ static FILE *pfFile;
+ png_byte pbSig[8];
+ int iBitDepth;
+ int iColorType;
+ double dGamma;
+ png_color_16 *pBackground;
+ png_uint_32 ulChannels;
+ png_uint_32 ulRowBytes;
+ png_byte *pbImageData = *ppbImageData;
+ static png_byte **ppbRowPointers = NULL;
+ int i;
+
+ // open the PNG input file
+
+ if (!pstrFileName)
+ {
+ *ppbImageData = pbImageData = NULL;
+ return FALSE;
+ }
+
+ if (!(pfFile = fopen(pstrFileName, "rb")))
+ {
+ *ppbImageData = pbImageData = NULL;
+ return FALSE;
+ }
+
+ // first check the eight byte PNG signature
+
+ fread(pbSig, 1, 8, pfFile);
+ if (!png_check_sig(pbSig, 8))
+ {
+ *ppbImageData = pbImageData = NULL;
+ return FALSE;
+ }
+
+ // create the two png(-info) structures
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
+ (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
+ if (!png_ptr)
+ {
+ *ppbImageData = pbImageData = NULL;
+ return FALSE;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ *ppbImageData = pbImageData = NULL;
+ return FALSE;
+ }
+
+ Try
+ {
+
+ // initialize the png structure
+
+#if !defined(PNG_NO_STDIO)
+ png_init_io(png_ptr, pfFile);
+#else
+ png_set_read_fn(png_ptr, (png_voidp)pfFile, png_read_data);
+#endif
+
+ png_set_sig_bytes(png_ptr, 8);
+
+ // read all PNG info up to image data
+
+ png_read_info(png_ptr, info_ptr);
+
+ // get width, height, bit-depth and color-type
+
+ png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth,
+ &iColorType, NULL, NULL, NULL);
+
+ // expand images of all color-type and bit-depth to 3x8 bit RGB images
+ // let the library process things like alpha, transparency, background
+
+ if (iBitDepth == 16)
+ png_set_strip_16(png_ptr);
+ if (iColorType == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+ if (iBitDepth < 8)
+ png_set_expand(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+ if (iColorType == PNG_COLOR_TYPE_GRAY ||
+ iColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+ // set the background color to draw transparent and alpha images over.
+ if (png_get_bKGD(png_ptr, info_ptr, &pBackground))
+ {
+ png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ pBkgColor->red = (byte) pBackground->red;
+ pBkgColor->green = (byte) pBackground->green;
+ pBkgColor->blue = (byte) pBackground->blue;
+ }
+ else
+ {
+ pBkgColor = NULL;
+ }
+
+ // if required set gamma conversion
+ if (png_get_gAMA(png_ptr, info_ptr, &dGamma))
+ png_set_gamma(png_ptr, (double) 2.2, dGamma);
+
+ // after the transformations have been registered update info_ptr data
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ // get again width, height and the new bit-depth and color-type
+
+ png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth,
+ &iColorType, NULL, NULL, NULL);
+
+
+ // row_bytes is the width x number of channels
+
+ ulRowBytes = png_get_rowbytes(png_ptr, info_ptr);
+ ulChannels = png_get_channels(png_ptr, info_ptr);
+
+ *piChannels = ulChannels;
+
+ // now we can allocate memory to store the image
+
+ if (pbImageData)
+ {
+ free (pbImageData);
+ pbImageData = NULL;
+ }
+ if ((pbImageData = (png_byte *) malloc(ulRowBytes * (*piHeight)
+ * sizeof(png_byte))) == NULL)
+ {
+ png_error(png_ptr, "Visual PNG: out of memory");
+ }
+ *ppbImageData = pbImageData;
+
+ // and allocate memory for an array of row-pointers
+
+ if ((ppbRowPointers = (png_bytepp) malloc((*piHeight)
+ * sizeof(png_bytep))) == NULL)
+ {
+ png_error(png_ptr, "Visual PNG: out of memory");
+ }
+
+ // set the individual row-pointers to point at the correct offsets
+
+ for (i = 0; i < (*piHeight); i++)
+ ppbRowPointers[i] = pbImageData + i * ulRowBytes;
+
+ // now we can go ahead and just read the whole image
+
+ png_read_image(png_ptr, ppbRowPointers);
+
+ // read the additional chunks in the PNG file (not really needed)
+
+ png_read_end(png_ptr, NULL);
+
+ // and we're done
+
+ free (ppbRowPointers);
+ ppbRowPointers = NULL;
+
+ // yepp, done
+ }
+
+ Catch (msg)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+ *ppbImageData = pbImageData = NULL;
+
+ if(ppbRowPointers)
+ free (ppbRowPointers);
+
+ fclose(pfFile);
+
+ return FALSE;
+ }
+
+ fclose (pfFile);
+
+ return TRUE;
+}
+
+
+BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData,
+ int iWidth, int iHeight, png_color bkgColor)
+{
+ const int ciBitDepth = 8;
+ const int ciChannels = 3;
+
+ static FILE *pfFile;
+ png_uint_32 ulRowBytes;
+ static png_byte **ppbRowPointers = NULL;
+ int i;
+
+ // open the PNG output file
+
+ if (!pstrFileName)
+ return FALSE;
+
+ if (!(pfFile = fopen(pstrFileName, "wb")))
+ return FALSE;
+
+ // prepare the standard PNG structures
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
+ (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
+ if (!png_ptr)
+ {
+ fclose(pfFile);
+ return FALSE;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ fclose(pfFile);
+ png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
+ return FALSE;
+ }
+
+ Try
+ {
+ // initialize the png structure
+
+#if !defined(PNG_NO_STDIO)
+ png_init_io(png_ptr, pfFile);
+#else
+ png_set_write_fn(png_ptr, (png_voidp)pfFile, png_write_data, png_flush);
+#endif
+
+ // we're going to write a very simple 3x8 bit RGB image
+
+ png_set_IHDR(png_ptr, info_ptr, iWidth, iHeight, ciBitDepth,
+ PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
+ PNG_FILTER_TYPE_BASE);
+
+ // write the file header information
+
+ png_write_info(png_ptr, info_ptr);
+
+ // swap the BGR pixels in the DiData structure to RGB
+
+ png_set_bgr(png_ptr);
+
+ // row_bytes is the width x number of channels
+
+ ulRowBytes = iWidth * ciChannels;
+
+ // we can allocate memory for an array of row-pointers
+
+ if ((ppbRowPointers = (png_bytepp) malloc(iHeight * sizeof(png_bytep))) == NULL)
+ Throw "Visualpng: Out of memory";
+
+ // set the individual row-pointers to point at the correct offsets
+
+ for (i = 0; i < iHeight; i++)
+ ppbRowPointers[i] = pDiData + i * (((ulRowBytes + 3) >> 2) << 2);
+
+ // write out the entire image data in one call
+
+ png_write_image (png_ptr, ppbRowPointers);
+
+ // write the additional chunks to the PNG file (not really needed)
+
+ png_write_end(png_ptr, info_ptr);
+
+ // and we're done
+
+ free (ppbRowPointers);
+ ppbRowPointers = NULL;
+
+ // clean up after the write, and free any memory allocated
+
+ png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
+
+ // yepp, done
+ }
+
+ Catch (msg)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
+
+ if(ppbRowPointers)
+ free (ppbRowPointers);
+
+ fclose(pfFile);
+
+ return FALSE;
+ }
+
+ fclose (pfFile);
+
+ return TRUE;
+}
+
+#ifdef PNG_NO_STDIO
+
+static void
+png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_size_t check;
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+ check = (png_size_t)fread(data, (png_size_t)1, length,
+ (FILE *)png_ptr->io_ptr);
+
+ if (check != length)
+ {
+ png_error(png_ptr, "Read Error");
+ }
+}
+
+static void
+png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+
+ check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+
+static void
+png_flush(png_structp png_ptr)
+{
+ FILE *io_ptr;
+ io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
+ if (io_ptr != NULL)
+ fflush(io_ptr);
+}
+
+#endif
+
+//-----------------
+// end of source
+//-----------------
diff --git a/contrib/visupng/PngFile.h b/contrib/visupng/PngFile.h
new file mode 100644
index 0000000..a900fd4
--- /dev/null
+++ b/contrib/visupng/PngFile.h
@@ -0,0 +1,27 @@
+//------------------------------------------
+// PNGFILE.H -- Header File for pngfile.c
+//------------------------------------------
+
+// Copyright 2000, Willem van Schaik. For conditions of distribution and
+// use, see the copyright/license/disclaimer notice in png.h
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+void PngFileInitialize (HWND hwnd) ;
+BOOL PngFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) ;
+BOOL PngFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) ;
+
+BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData,
+ int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor);
+BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData,
+ int iWidth, int iHeight, png_color BkgColor);
+
+#if defined(PNG_NO_STDIO)
+static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length);
+static void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length);
+static void png_flush(png_structp png_ptr);
+#endif
+
diff --git a/contrib/visupng/README.txt b/contrib/visupng/README.txt
new file mode 100644
index 0000000..4a753d8
--- /dev/null
+++ b/contrib/visupng/README.txt
@@ -0,0 +1,58 @@
+Microsoft Developer Studio Build File, Format Version 6.00 for VisualPng
+------------------------------------------------------------------------
+
+Copyright 2000, Willem van Schaik. For conditions of distribution and
+use, see the copyright/license/disclaimer notice in png.h
+
+As a PNG .dll demo VisualPng is finished. More features would only hinder
+the program's objective. However, further extensions (like support for other
+graphics formats) are in development. To get these, or for pre-compiled
+binaries, go to "http://www.schaik.com/png/visualpng.html".
+
+------------------------------------------------------------------------
+
+Assumes that
+
+ libpng DLLs and LIBs are in ..\..\projects\msvc\win32\libpng
+ zlib DLLs and LIBs are in ..\..\projects\msvc\win32\zlib
+ libpng header files are in ..\..\..\libpng
+ zlib header files are in ..\..\..\zlib
+ the pngsuite images are in ..\pngsuite
+
+To build:
+
+1) On the main menu Select "Build|Set Active configuration".
+ Choose the configuration that corresponds to the library you want to test.
+ This library must have been built using the libpng MS project located in
+ the "..\..\mscv" subdirectory.
+
+2) Select "Build|Clean"
+
+3) Select "Build|Rebuild All"
+
+4) After compiling and linking VisualPng will be started to view an image
+ from the PngSuite directory. Press Ctrl-N (and Ctrl-V) for other images.
+
+
+To install:
+
+When distributing VisualPng (or a further development) the following options
+are available:
+
+1) Build the program with the configuration "Win32 LIB" and you only need to
+ include the executable from the ./lib directory in your distribution.
+
+2) Build the program with the configuration "Win32 DLL" and you need to put
+ in your distribution the executable from the ./dll directory and the dll's
+ libpng1.dll, zlib.dll and msvcrt.dll. These need to be in the user's PATH.
+
+
+Willem van Schaik
+Calgary, June 6th 2000
+
+P.S. VisualPng was written based on preliminary work of:
+
+ - Simon-Pierre Cadieux
+ - Glenn Randers-Pehrson
+ - Greg Roelofs
+
diff --git a/contrib/visupng/VisualPng.c b/contrib/visupng/VisualPng.c
new file mode 100644
index 0000000..f2cf6ee
--- /dev/null
+++ b/contrib/visupng/VisualPng.c
@@ -0,0 +1,961 @@
+//------------------------------------
+// VisualPng.C -- Shows a PNG image
+//------------------------------------
+
+// Copyright 2000, Willem van Schaik. For conditions of distribution and
+// use, see the copyright/license/disclaimer notice in png.h
+
+// switches
+
+// defines
+
+#define PROGNAME "VisualPng"
+#define LONGNAME "Win32 Viewer for PNG-files"
+#define VERSION "1.0 of 2000 June 07"
+
+// constants
+
+#define MARGIN 8
+
+// standard includes
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+// application includes
+
+#include "png.h"
+#include "pngfile.h"
+#include "resource.h"
+
+// macros
+
+// function prototypes
+
+LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
+BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
+
+BOOL CenterAbout (HWND hwndChild, HWND hwndParent);
+
+BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount,
+ int *pFileIndex);
+
+BOOL SearchPngList (TCHAR *pFileList, int FileCount, int *pFileIndex,
+ PTSTR pstrPrevName, PTSTR pstrNextName);
+
+BOOL LoadImageFile(HWND hwnd, PTSTR pstrPathName,
+ png_byte **ppbImage, int *pxImgSize, int *pyImgSize, int *piChannels,
+ png_color *pBkgColor);
+
+BOOL DisplayImage (HWND hwnd, BYTE **ppDib,
+ BYTE **ppDiData, int cxWinSize, int cyWinSize,
+ BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
+ BOOL bStretched);
+
+BOOL InitBitmap (
+ BYTE *pDiData, int cxWinSize, int cyWinSize);
+
+BOOL FillBitmap (
+ BYTE *pDiData, int cxWinSize, int cyWinSize,
+ BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
+ BOOL bStretched);
+
+// a few global variables
+
+static char *szProgName = PROGNAME;
+static char *szAppName = LONGNAME;
+static char *szIconName = PROGNAME;
+static char szCmdFileName [MAX_PATH];
+
+// MAIN routine
+
+int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ PSTR szCmdLine, int iCmdShow)
+{
+ HACCEL hAccel;
+ HWND hwnd;
+ MSG msg;
+ WNDCLASS wndclass;
+ int ixBorders, iyBorders;
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon (hInstance, szIconName) ;
+ wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wndclass.hbrBackground = NULL; // (HBRUSH) GetStockObject (GRAY_BRUSH);
+ wndclass.lpszMenuName = szProgName;
+ wndclass.lpszClassName = szProgName;
+
+ if (!RegisterClass (&wndclass))
+ {
+ MessageBox (NULL, TEXT ("Error: this program requires Windows NT!"),
+ szProgName, MB_ICONERROR);
+ return 0;
+ }
+
+ // if filename given on commandline, store it
+ if ((szCmdLine != NULL) && (*szCmdLine != '\0'))
+ if (szCmdLine[0] == '"')
+ strncpy (szCmdFileName, szCmdLine + 1, strlen(szCmdLine) - 2);
+ else
+ strcpy (szCmdFileName, szCmdLine);
+ else
+ strcpy (szCmdFileName, "");
+
+ // calculate size of window-borders
+ ixBorders = 2 * (GetSystemMetrics (SM_CXBORDER) +
+ GetSystemMetrics (SM_CXDLGFRAME));
+ iyBorders = 2 * (GetSystemMetrics (SM_CYBORDER) +
+ GetSystemMetrics (SM_CYDLGFRAME)) +
+ GetSystemMetrics (SM_CYCAPTION) +
+ GetSystemMetrics (SM_CYMENUSIZE) +
+ 1; /* WvS: don't ask me why? */
+
+ hwnd = CreateWindow (szProgName, szAppName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ 512 + 2 * MARGIN + ixBorders, 384 + 2 * MARGIN + iyBorders,
+// CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, hInstance, NULL);
+
+ ShowWindow (hwnd, iCmdShow);
+ UpdateWindow (hwnd);
+
+ hAccel = LoadAccelerators (hInstance, szProgName);
+
+ while (GetMessage (&msg, NULL, 0, 0))
+ {
+ if (!TranslateAccelerator (hwnd, hAccel, &msg))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+ return msg.wParam;
+}
+
+LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,
+ LPARAM lParam)
+{
+ static HINSTANCE hInstance ;
+ static HDC hdc;
+ static PAINTSTRUCT ps;
+ static HMENU hMenu;
+
+ static BITMAPFILEHEADER *pbmfh;
+ static BITMAPINFOHEADER *pbmih;
+ static BYTE *pbImage;
+ static int cxWinSize, cyWinSize;
+ static int cxImgSize, cyImgSize;
+ static int cImgChannels;
+ static png_color bkgColor = {127, 127, 127};
+
+ static BOOL bStretched = TRUE;
+
+ static BYTE *pDib = NULL;
+ static BYTE *pDiData = NULL;
+
+ static TCHAR szImgPathName [MAX_PATH];
+ static TCHAR szTitleName [MAX_PATH];
+
+ static TCHAR *pPngFileList = NULL;
+ static int iPngFileCount;
+ static int iPngFileIndex;
+
+ BOOL bOk;
+
+ switch (message)
+ {
+ case WM_CREATE:
+ hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
+ PngFileInitialize (hwnd);
+
+ strcpy (szImgPathName, "");
+
+ // in case we process file given on command-line
+
+ if (szCmdFileName[0] != '\0')
+ {
+ strcpy (szImgPathName, szCmdFileName);
+
+ // read the other png-files in the directory for later
+ // next/previous commands
+
+ BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount,
+ &iPngFileIndex);
+
+ // load the image from file
+
+ if (!LoadImageFile (hwnd, szImgPathName,
+ &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
+ return 0;
+
+ // invalidate the client area for later update
+
+ InvalidateRect (hwnd, NULL, TRUE);
+
+ // display the PNG into the DIBitmap
+
+ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
+ pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
+ }
+
+ return 0;
+
+ case WM_SIZE:
+ cxWinSize = LOWORD (lParam);
+ cyWinSize = HIWORD (lParam);
+
+ // invalidate the client area for later update
+
+ InvalidateRect (hwnd, NULL, TRUE);
+
+ // display the PNG into the DIBitmap
+
+ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
+ pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
+
+ return 0;
+
+ case WM_INITMENUPOPUP:
+ hMenu = GetMenu (hwnd);
+
+ if (pbImage)
+ EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_ENABLED);
+ else
+ EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_GRAYED);
+
+ return 0;
+
+ case WM_COMMAND:
+ hMenu = GetMenu (hwnd);
+
+ switch (LOWORD (wParam))
+ {
+ case IDM_FILE_OPEN:
+
+ // show the File Open dialog box
+
+ if (!PngFileOpenDlg (hwnd, szImgPathName, szTitleName))
+ return 0;
+
+ // read the other png-files in the directory for later
+ // next/previous commands
+
+ BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount,
+ &iPngFileIndex);
+
+ // load the image from file
+
+ if (!LoadImageFile (hwnd, szImgPathName,
+ &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
+ return 0;
+
+ // invalidate the client area for later update
+
+ InvalidateRect (hwnd, NULL, TRUE);
+
+ // display the PNG into the DIBitmap
+
+ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
+ pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
+
+ return 0;
+
+ case IDM_FILE_SAVE:
+
+ // show the File Save dialog box
+
+ if (!PngFileSaveDlg (hwnd, szImgPathName, szTitleName))
+ return 0;
+
+ // save the PNG to a disk file
+
+ SetCursor (LoadCursor (NULL, IDC_WAIT));
+ ShowCursor (TRUE);
+
+ bOk = PngSaveImage (szImgPathName, pDiData, cxWinSize, cyWinSize,
+ bkgColor);
+
+ ShowCursor (FALSE);
+ SetCursor (LoadCursor (NULL, IDC_ARROW));
+
+ if (!bOk)
+ MessageBox (hwnd, TEXT ("Error in saving the PNG image"),
+ szProgName, MB_ICONEXCLAMATION | MB_OK);
+ return 0;
+
+ case IDM_FILE_NEXT:
+
+ // read next entry in the directory
+
+ if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex,
+ NULL, szImgPathName))
+ {
+ if (strcmp (szImgPathName, "") == 0)
+ return 0;
+
+ // load the image from file
+
+ if (!LoadImageFile (hwnd, szImgPathName, &pbImage,
+ &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
+ return 0;
+
+ // invalidate the client area for later update
+
+ InvalidateRect (hwnd, NULL, TRUE);
+
+ // display the PNG into the DIBitmap
+
+ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
+ pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
+ }
+
+ return 0;
+
+ case IDM_FILE_PREVIOUS:
+
+ // read previous entry in the directory
+
+ if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex,
+ szImgPathName, NULL))
+ {
+
+ if (strcmp (szImgPathName, "") == 0)
+ return 0;
+
+ // load the image from file
+
+ if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize,
+ &cyImgSize, &cImgChannels, &bkgColor))
+ return 0;
+
+ // invalidate the client area for later update
+
+ InvalidateRect (hwnd, NULL, TRUE);
+
+ // display the PNG into the DIBitmap
+
+ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
+ pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
+ }
+
+ return 0;
+
+ case IDM_FILE_EXIT:
+
+ // more cleanup needed...
+
+ // free image buffer
+
+ if (pDib != NULL)
+ {
+ free (pDib);
+ pDib = NULL;
+ }
+
+ // free file-list
+
+ if (pPngFileList != NULL)
+ {
+ free (pPngFileList);
+ pPngFileList = NULL;
+ }
+
+ // let's go ...
+
+ exit (0);
+
+ return 0;
+
+ case IDM_OPTIONS_STRETCH:
+ bStretched = !bStretched;
+ if (bStretched)
+ CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_CHECKED);
+ else
+ CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_UNCHECKED);
+
+ // invalidate the client area for later update
+
+ InvalidateRect (hwnd, NULL, TRUE);
+
+ // display the PNG into the DIBitmap
+
+ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
+ pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
+
+ return 0;
+
+ case IDM_HELP_ABOUT:
+ DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc) ;
+ return 0;
+
+ } // end switch
+
+ break;
+
+ case WM_PAINT:
+ hdc = BeginPaint (hwnd, &ps);
+
+ if (pDib)
+ SetDIBitsToDevice (hdc, 0, 0, cxWinSize, cyWinSize, 0, 0,
+ 0, cyWinSize, pDiData, (BITMAPINFO *) pDib, DIB_RGB_COLORS);
+
+ EndPaint (hwnd, &ps);
+ return 0;
+
+ case WM_DESTROY:
+ if (pbmfh)
+ {
+ free (pbmfh);
+ pbmfh = NULL;
+ }
+
+ PostQuitMessage (0);
+ return 0;
+ }
+
+ return DefWindowProc (hwnd, message, wParam, lParam);
+}
+
+BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG :
+ ShowWindow (hDlg, SW_HIDE);
+ CenterAbout (hDlg, GetWindow (hDlg, GW_OWNER));
+ ShowWindow (hDlg, SW_SHOW);
+ return TRUE ;
+
+ case WM_COMMAND :
+ switch (LOWORD (wParam))
+ {
+ case IDOK :
+ case IDCANCEL :
+ EndDialog (hDlg, 0) ;
+ return TRUE ;
+ }
+ break ;
+ }
+ return FALSE ;
+}
+
+//---------------
+// CenterAbout
+//---------------
+
+BOOL CenterAbout (HWND hwndChild, HWND hwndParent)
+{
+ RECT rChild, rParent, rWorkArea;
+ int wChild, hChild, wParent, hParent;
+ int xNew, yNew;
+ BOOL bResult;
+
+ // Get the Height and Width of the child window
+ GetWindowRect (hwndChild, &rChild);
+ wChild = rChild.right - rChild.left;
+ hChild = rChild.bottom - rChild.top;
+
+ // Get the Height and Width of the parent window
+ GetWindowRect (hwndParent, &rParent);
+ wParent = rParent.right - rParent.left;
+ hParent = rParent.bottom - rParent.top;
+
+ // Get the limits of the 'workarea'
+ bResult = SystemParametersInfo(
+ SPI_GETWORKAREA, // system parameter to query or set
+ sizeof(RECT),
+ &rWorkArea,
+ 0);
+ if (!bResult) {
+ rWorkArea.left = rWorkArea.top = 0;
+ rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
+ rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
+ }
+
+ // Calculate new X position, then adjust for workarea
+ xNew = rParent.left + ((wParent - wChild) /2);
+ if (xNew < rWorkArea.left) {
+ xNew = rWorkArea.left;
+ } else if ((xNew+wChild) > rWorkArea.right) {
+ xNew = rWorkArea.right - wChild;
+ }
+
+ // Calculate new Y position, then adjust for workarea
+ yNew = rParent.top + ((hParent - hChild) /2);
+ if (yNew < rWorkArea.top) {
+ yNew = rWorkArea.top;
+ } else if ((yNew+hChild) > rWorkArea.bottom) {
+ yNew = rWorkArea.bottom - hChild;
+ }
+
+ // Set it, and return
+ return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE |
+ SWP_NOZORDER);
+}
+
+//----------------
+// BuildPngList
+//----------------
+
+BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount,
+ int *pFileIndex)
+{
+ static TCHAR szImgPathName [MAX_PATH];
+ static TCHAR szImgFileName [MAX_PATH];
+ static TCHAR szImgFindName [MAX_PATH];
+
+ WIN32_FIND_DATA finddata;
+ HANDLE hFind;
+
+ static TCHAR szTmp [MAX_PATH];
+ BOOL bOk;
+ int i, ii;
+ int j, jj;
+
+ // free previous file-list
+
+ if (*ppFileList != NULL)
+ {
+ free (*ppFileList);
+ *ppFileList = NULL;
+ }
+
+ // extract foldername, filename and search-name
+
+ strcpy (szImgPathName, pstrPathName);
+ strcpy (szImgFileName, strrchr (pstrPathName, '\\') + 1);
+
+ strcpy (szImgFindName, szImgPathName);
+ *(strrchr (szImgFindName, '\\') + 1) = '\0';
+ strcat (szImgFindName, "*.png");
+
+ // first cycle: count number of files in directory for memory allocation
+
+ *pFileCount = 0;
+
+ hFind = FindFirstFile(szImgFindName, &finddata);
+ bOk = (hFind != (HANDLE) -1);
+
+ while (bOk)
+ {
+ *pFileCount += 1;
+ bOk = FindNextFile(hFind, &finddata);
+ }
+ FindClose(hFind);
+
+ // allocation memory for file-list
+
+ *ppFileList = (TCHAR *) malloc (*pFileCount * MAX_PATH);
+
+ // second cycle: read directory and store filenames in file-list
+
+ hFind = FindFirstFile(szImgFindName, &finddata);
+ bOk = (hFind != (HANDLE) -1);
+
+ i = 0;
+ ii = 0;
+ while (bOk)
+ {
+ strcpy (*ppFileList + ii, szImgPathName);
+ strcpy (strrchr(*ppFileList + ii, '\\') + 1, finddata.cFileName);
+
+ if (strcmp(pstrPathName, *ppFileList + ii) == 0)
+ *pFileIndex = i;
+
+ ii += MAX_PATH;
+ i++;
+
+ bOk = FindNextFile(hFind, &finddata);
+ }
+ FindClose(hFind);
+
+ // finally we must sort the file-list
+
+ for (i = 0; i < *pFileCount - 1; i++)
+ {
+ ii = i * MAX_PATH;
+ for (j = i+1; j < *pFileCount; j++)
+ {
+ jj = j * MAX_PATH;
+ if (strcmp (*ppFileList + ii, *ppFileList + jj) > 0)
+ {
+ strcpy (szTmp, *ppFileList + jj);
+ strcpy (*ppFileList + jj, *ppFileList + ii);
+ strcpy (*ppFileList + ii, szTmp);
+
+ // check if this was the current image that we moved
+
+ if (*pFileIndex == i)
+ *pFileIndex = j;
+ else
+ if (*pFileIndex == j)
+ *pFileIndex = i;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+//----------------
+// SearchPngList
+//----------------
+
+BOOL SearchPngList (
+ TCHAR *pFileList, int FileCount, int *pFileIndex,
+ PTSTR pstrPrevName, PTSTR pstrNextName)
+{
+ if (FileCount > 0)
+ {
+ // get previous entry
+
+ if (pstrPrevName != NULL)
+ {
+ if (*pFileIndex > 0)
+ *pFileIndex -= 1;
+ else
+ *pFileIndex = FileCount - 1;
+
+ strcpy (pstrPrevName, pFileList + (*pFileIndex * MAX_PATH));
+ }
+
+ // get next entry
+
+ if (pstrNextName != NULL)
+ {
+ if (*pFileIndex < FileCount - 1)
+ *pFileIndex += 1;
+ else
+ *pFileIndex = 0;
+
+ strcpy (pstrNextName, pFileList + (*pFileIndex * MAX_PATH));
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+//-----------------
+// LoadImageFile
+//-----------------
+
+BOOL LoadImageFile (HWND hwnd, PTSTR pstrPathName,
+ png_byte **ppbImage, int *pxImgSize, int *pyImgSize,
+ int *piChannels, png_color *pBkgColor)
+{
+ static TCHAR szTmp [MAX_PATH];
+
+ // if there's an existing PNG, free the memory
+
+ if (*ppbImage)
+ {
+ free (*ppbImage);
+ *ppbImage = NULL;
+ }
+
+ // Load the entire PNG into memory
+
+ SetCursor (LoadCursor (NULL, IDC_WAIT));
+ ShowCursor (TRUE);
+
+ PngLoadImage (pstrPathName, ppbImage, pxImgSize, pyImgSize, piChannels,
+ pBkgColor);
+
+ ShowCursor (FALSE);
+ SetCursor (LoadCursor (NULL, IDC_ARROW));
+
+ if (*ppbImage != NULL)
+ {
+ sprintf (szTmp, "VisualPng - %s", strrchr(pstrPathName, '\\') + 1);
+ SetWindowText (hwnd, szTmp);
+ }
+ else
+ {
+ MessageBox (hwnd, TEXT ("Error in loading the PNG image"),
+ szProgName, MB_ICONEXCLAMATION | MB_OK);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//----------------
+// DisplayImage
+//----------------
+
+BOOL DisplayImage (HWND hwnd, BYTE **ppDib,
+ BYTE **ppDiData, int cxWinSize, int cyWinSize,
+ BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
+ BOOL bStretched)
+{
+ BYTE *pDib = *ppDib;
+ BYTE *pDiData = *ppDiData;
+ // BITMAPFILEHEADER *pbmfh;
+ BITMAPINFOHEADER *pbmih;
+ WORD wDIRowBytes;
+ png_color bkgBlack = {0, 0, 0};
+ png_color bkgGray = {127, 127, 127};
+ png_color bkgWhite = {255, 255, 255};
+
+ // allocate memory for the Device Independant bitmap
+
+ wDIRowBytes = (WORD) ((3 * cxWinSize + 3L) >> 2) << 2;
+
+ if (pDib)
+ {
+ free (pDib);
+ pDib = NULL;
+ }
+
+ if (!(pDib = (BYTE *) malloc (sizeof(BITMAPINFOHEADER) +
+ wDIRowBytes * cyWinSize)))
+ {
+ MessageBox (hwnd, TEXT ("Error in displaying the PNG image"),
+ szProgName, MB_ICONEXCLAMATION | MB_OK);
+ *ppDib = pDib = NULL;
+ return FALSE;
+ }
+ *ppDib = pDib;
+ memset (pDib, 0, sizeof(BITMAPINFOHEADER));
+
+ // initialize the dib-structure
+
+ pbmih = (BITMAPINFOHEADER *) pDib;
+ pbmih->biSize = sizeof(BITMAPINFOHEADER);
+ pbmih->biWidth = cxWinSize;
+ pbmih->biHeight = -((long) cyWinSize);
+ pbmih->biPlanes = 1;
+ pbmih->biBitCount = 24;
+ pbmih->biCompression = 0;
+ pDiData = pDib + sizeof(BITMAPINFOHEADER);
+ *ppDiData = pDiData;
+
+ // first fill bitmap with gray and image border
+
+ InitBitmap (pDiData, cxWinSize, cyWinSize);
+
+ // then fill bitmap with image
+
+ if (pbImage)
+ {
+ FillBitmap (
+ pDiData, cxWinSize, cyWinSize,
+ pbImage, cxImgSize, cyImgSize, cImgChannels,
+ bStretched);
+ }
+
+ return TRUE;
+}
+
+//--------------
+// InitBitmap
+//--------------
+
+BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize)
+{
+ BYTE *dst;
+ int x, y, col;
+
+ // initialize the background with gray
+
+ dst = pDiData;
+ for (y = 0; y < cyWinSize; y++)
+ {
+ col = 0;
+ for (x = 0; x < cxWinSize; x++)
+ {
+ // fill with GRAY
+ *dst++ = 127;
+ *dst++ = 127;
+ *dst++ = 127;
+ col += 3;
+ }
+ // rows start on 4 byte boundaries
+ while ((col % 4) != 0)
+ {
+ dst++;
+ col++;
+ }
+ }
+
+ return TRUE;
+}
+
+//--------------
+// FillBitmap
+//--------------
+
+BOOL FillBitmap (
+ BYTE *pDiData, int cxWinSize, int cyWinSize,
+ BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
+ BOOL bStretched)
+{
+ BYTE *pStretchedImage;
+ BYTE *pImg;
+ BYTE *src, *dst;
+ BYTE r, g, b, a;
+ const int cDIChannels = 3;
+ WORD wImgRowBytes;
+ WORD wDIRowBytes;
+ int cxNewSize, cyNewSize;
+ int cxImgPos, cyImgPos;
+ int xImg, yImg;
+ int xWin, yWin;
+ int xOld, yOld;
+ int xNew, yNew;
+
+ if (bStretched)
+ {
+ cxNewSize = cxWinSize - 2 * MARGIN;
+ cyNewSize = cyWinSize - 2 * MARGIN;
+
+ // stretch the image to it's window determined size
+
+ // the following two are the same, but the first has side-effects
+ // because of rounding
+// if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize))
+ if ((cyNewSize * cxImgSize) > (cyImgSize * cxNewSize))
+ {
+ cyNewSize = cxNewSize * cyImgSize / cxImgSize;
+ cxImgPos = MARGIN;
+ cyImgPos = (cyWinSize - cyNewSize) / 2;
+ }
+ else
+ {
+ cxNewSize = cyNewSize * cxImgSize / cyImgSize;
+ cyImgPos = MARGIN;
+ cxImgPos = (cxWinSize - cxNewSize) / 2;
+ }
+
+ pStretchedImage = malloc (cImgChannels * cxNewSize * cyNewSize);
+ pImg = pStretchedImage;
+
+ for (yNew = 0; yNew < cyNewSize; yNew++)
+ {
+ yOld = yNew * cyImgSize / cyNewSize;
+ for (xNew = 0; xNew < cxNewSize; xNew++)
+ {
+ xOld = xNew * cxImgSize / cxNewSize;
+
+ r = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 0);
+ g = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 1);
+ b = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 2);
+ *pImg++ = r;
+ *pImg++ = g;
+ *pImg++ = b;
+ if (cImgChannels == 4)
+ {
+ a = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld)
+ + 3);
+ *pImg++ = a;
+ }
+ }
+ }
+
+ // calculate row-bytes
+
+ wImgRowBytes = cImgChannels * cxNewSize;
+ wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
+
+ // copy image to screen
+
+ for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++)
+ {
+ if (yWin >= cyWinSize - cyImgPos)
+ break;
+ src = pStretchedImage + yImg * wImgRowBytes;
+ dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
+
+ for (xImg = 0, xWin = cxImgPos; xImg < cxNewSize; xImg++, xWin++)
+ {
+ if (xWin >= cxWinSize - cxImgPos)
+ break;
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ *dst++ = b; /* note the reverse order */
+ *dst++ = g;
+ *dst++ = r;
+ if (cImgChannels == 4)
+ {
+ a = *src++;
+ }
+ }
+ }
+
+ // free memory
+
+ if (pStretchedImage != NULL)
+ {
+ free (pStretchedImage);
+ pStretchedImage = NULL;
+ }
+
+ }
+
+ // process the image not-stretched
+
+ else
+ {
+ // calculate the central position
+
+ cxImgPos = (cxWinSize - cxImgSize) / 2;
+ cyImgPos = (cyWinSize - cyImgSize) / 2;
+
+ // check for image larger than window
+
+ if (cxImgPos < MARGIN)
+ cxImgPos = MARGIN;
+ if (cyImgPos < MARGIN)
+ cyImgPos = MARGIN;
+
+ // calculate both row-bytes
+
+ wImgRowBytes = cImgChannels * cxImgSize;
+ wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
+
+ // copy image to screen
+
+ for (yImg = 0, yWin = cyImgPos; yImg < cyImgSize; yImg++, yWin++)
+ {
+ if (yWin >= cyWinSize - MARGIN)
+ break;
+ src = pbImage + yImg * wImgRowBytes;
+ dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
+
+ for (xImg = 0, xWin = cxImgPos; xImg < cxImgSize; xImg++, xWin++)
+ {
+ if (xWin >= cxWinSize - MARGIN)
+ break;
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ *dst++ = b; /* note the reverse order */
+ *dst++ = g;
+ *dst++ = r;
+ if (cImgChannels == 4)
+ {
+ a = *src++;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+//-----------------
+// end of source
+//-----------------
diff --git a/contrib/visupng/VisualPng.dsp b/contrib/visupng/VisualPng.dsp
new file mode 100644
index 0000000..c13c5a7
--- /dev/null
+++ b/contrib/visupng/VisualPng.dsp
@@ -0,0 +1,147 @@
+# Microsoft Developer Studio Project File - Name="VisualPng" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=VisualPng - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "VisualPng.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "VisualPng.mak" CFG="VisualPng - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "VisualPng - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "VisualPng - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "VisualPng - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /O2 /I "..\.." /I "..\..\..\zlib" /D "WIN32" /D "NDEBUG" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /MD /W3 /O2 /I "..\.." /I "..\..\..\zlib" /D "WIN32" /D "NDEBUG" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 ..\..\projects\visualc6\Win32_LIB_Release\libpng.lib ..\..\..\zlib\projects\visualc6\Win32_LIB_Release\zlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# Begin Special Build Tool
+OutDir=.\Release
+SOURCE="$(InputPath)"
+PostBuild_Cmds=$(outdir)\VisualPng.exe ..\..\contrib\pngsuite\basn6a16.png
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "VisualPng - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /ZI /Od /I "..\.." /I "..\..\..\zlib" /D "WIN32" /D "_DEBUG" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /GZ /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\.." /I "..\..\..\zlib" /D "WIN32" /D "_DEBUG" /D "PNG_NO_STDIO" /D "PNG_NO_GLOBAL_ARRAYS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 ..\..\projects\visualc6\Win32_LIB_Release\libpng.lib ..\..\..\zlib\projects\visualc6\Win32_LIB_Release\zlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept
+# Begin Special Build Tool
+OutDir=.\Debug
+SOURCE="$(InputPath)"
+PostBuild_Cmds=$(outdir)\VisualPng.exe ..\..\contrib\pngsuite\basn6a16.png
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "VisualPng - Win32 Release"
+# Name "VisualPng - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\PngFile.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\VisualPng.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\cexcept.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PngFile.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\VisualPng.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\VisualPng.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/contrib/visupng/VisualPng.dsw b/contrib/visupng/VisualPng.dsw
new file mode 100644
index 0000000..17ad83a
--- /dev/null
+++ b/contrib/visupng/VisualPng.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "VisualPng"=.\VisualPng.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/contrib/visupng/VisualPng.ico b/contrib/visupng/VisualPng.ico
new file mode 100644
index 0000000..68aa371
--- /dev/null
+++ b/contrib/visupng/VisualPng.ico
Binary files differ
diff --git a/contrib/visupng/VisualPng.png b/contrib/visupng/VisualPng.png
new file mode 100644
index 0000000..c6aa80a
--- /dev/null
+++ b/contrib/visupng/VisualPng.png
Binary files differ
diff --git a/contrib/visupng/VisualPng.rc b/contrib/visupng/VisualPng.rc
new file mode 100644
index 0000000..151c68c
--- /dev/null
+++ b/contrib/visupng/VisualPng.rc
@@ -0,0 +1,152 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+VISUALPNG MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Open Image...\tCtrl+O", IDM_FILE_OPEN
+ MENUITEM "Save &As...", IDM_FILE_SAVE
+ MENUITEM SEPARATOR
+ MENUITEM "&Next Image\tCtrl+N", IDM_FILE_NEXT
+ MENUITEM "Pre&vious Image\tCtrl+V", IDM_FILE_PREVIOUS
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit\tAlt+X", IDM_FILE_EXIT
+ END
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Stretch", IDM_OPTIONS_STRETCH, CHECKED
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About", IDM_HELP_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+VISUALPNG ACCELERATORS DISCARDABLE
+BEGIN
+ "N", IDM_FILE_NEXT, VIRTKEY, CONTROL, NOINVERT
+ "O", IDM_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
+ "P", IDM_FILE_PREVIOUS, VIRTKEY, CONTROL, NOINVERT
+ "V", IDM_FILE_PREVIOUS, VIRTKEY, CONTROL, NOINVERT
+ "X", IDM_FILE_EXIT, VIRTKEY, ALT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+VISUALPNG ICON DISCARDABLE "VisualPng.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ABOUTBOX DIALOG DISCARDABLE 0, 0, 186, 94
+STYLE DS_MODALFRAME | WS_POPUP
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,68,67,50,14
+ CTEXT "VisualPng 1.0 - June 2000",IDC_STATIC,49,14,88,8
+ LTEXT "a PNG image viewer",IDC_STATIC,60,30,66,8
+ LTEXT "(c) Willem van Schaik, 2000",IDC_STATIC,48,52,90,8
+ LTEXT "to demonstrate the use of libpng in Visual C",
+ IDC_STATIC,25,38,136,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ "ABOUTBOX", DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 87
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/contrib/visupng/cexcept.h b/contrib/visupng/cexcept.h
new file mode 100644
index 0000000..dbea51e
--- /dev/null
+++ b/contrib/visupng/cexcept.h
@@ -0,0 +1,243 @@
+/*===
+cexcept.h 2.0.0 (2001-Jul-12-Thu)
+Adam M. Costello <amc@cs.berkeley.edu>
+
+An interface for exception-handling in ANSI C (C89 and subsequent ISO
+standards), developed jointly with Cosmin Truta <cosmin@cs.toronto.edu>.
+
+ Copyright (c) 2001 Adam M. Costello and Cosmin Truta. Everyone
+ is hereby granted permission to do whatever they like with this
+ file, provided that if they modify it they take reasonable steps to
+ avoid confusing or misleading people about the authors, version,
+ and terms of use of the derived file. The copyright holders make
+ no guarantees regarding this file, and are not responsible for any
+ damage resulting from its use.
+
+Only user-defined exceptions are supported, not "real" exceptions like
+division by zero or memory segmentation violations.
+
+If this interface is used by multiple .c files, they shouldn't include
+this header file directly. Instead, create a wrapper header file that
+includes this header file and then invokes the define_exception_type
+macro (see below), and let your .c files include that header file.
+
+The interface consists of one type, one well-known name, and six macros.
+
+
+define_exception_type(type_name);
+
+ This macro is used like an external declaration. It specifies
+ the type of object that gets copied from the exception thrower to
+ the exception catcher. The type_name can be any type that can be
+ assigned to, that is, a non-constant arithmetic type, struct, union,
+ or pointer. Examples:
+
+ define_exception_type(int);
+
+ enum exception { out_of_memory, bad_arguments, disk_full };
+ define_exception_type(enum exception);
+
+ struct exception { int code; const char *msg; };
+ define_exception_type(struct exception);
+
+ Because throwing an exception causes the object to be copied (not
+ just once, but twice), programmers may wish to consider size when
+ choosing the exception type.
+
+
+struct exception_context;
+
+ This type may be used after the define_exception_type() macro has
+ been invoked. A struct exception_context must be known to both
+ the thrower and the catcher. It is expected that there be one
+ context for each thread that uses exceptions. It would certainly
+ be dangerous for multiple threads to access the same context.
+ One thread can use multiple contexts, but that is likely to be
+ confusing and not typically useful. The application can allocate
+ this structure in any way it pleases--automatic, static, or dynamic.
+ The application programmer should pretend not to know the structure
+ members, which are subject to change.
+
+
+struct exception_context *the_exception_context;
+
+ The Try/Catch and Throw statements (described below) implicitly
+ refer to a context, using the name the_exception_context. It is
+ the application's responsibility to make sure that this name yields
+ the address of a mutable (non-constant) struct exception_context
+ wherever those statements are used. Subject to that constraint, the
+ application may declare a variable of this name anywhere it likes
+ (inside a function, in a parameter list, or externally), and may
+ use whatever storage class specifiers (static, extern, etc) or type
+ qualifiers (const, volatile, etc) it likes. Examples:
+
+ static struct exception_context
+ * const the_exception_context = &foo;
+
+ { struct exception_context *the_exception_context = bar; ... }
+
+ int blah(struct exception_context *the_exception_context, ...);
+
+ extern struct exception_context the_exception_context[1];
+
+ The last example illustrates a trick that avoids creating a pointer
+ object separate from the structure object.
+
+ The name could even be a macro, for example:
+
+ struct exception_context ec_array[numthreads];
+ #define the_exception_context (ec_array + thread_id)
+
+ Be aware that the_exception_context is used several times by the
+ Try/Catch/Throw macros, so it shouldn't be expensive or have side
+ effects. The expansion must be a drop-in replacement for an
+ identifier, so it's safest to put parentheses around it.
+
+
+void init_exception_context(struct exception_context *ec);
+
+ For context structures allocated statically (by an external
+ definition or using the "static" keyword), the implicit
+ initialization to all zeros is sufficient, but contexts allocated
+ by other means must be initialized using this macro before they
+ are used by a Try/Catch statement. It does no harm to initialize
+ a context more than once (by using this macro on a statically
+ allocated context, or using this macro twice on the same context),
+ but a context must not be re-initialized after it has been used by a
+ Try/Catch statement.
+
+
+Try statement
+Catch (expression) statement
+
+ The Try/Catch/Throw macros are capitalized in order to avoid
+ confusion with the C++ keywords, which have subtly different
+ semantics.
+
+ A Try/Catch statement has a syntax similar to an if/else statement,
+ except that the parenthesized expression goes after the second
+ keyword rather than the first. As with if/else, there are two
+ clauses, each of which may be a simple statement ending with a
+ semicolon or a brace-enclosed compound statement. But whereas
+ the else clause is optional, the Catch clause is required. The
+ expression must be a modifiable lvalue (something capable of being
+ assigned to) of the same type (disregarding type qualifiers) that
+ was passed to define_exception_type().
+
+ If a Throw that uses the same exception context as the Try/Catch is
+ executed within the Try clause (typically within a function called
+ by the Try clause), and the exception is not caught by a nested
+ Try/Catch statement, then a copy of the exception will be assigned
+ to the expression, and control will jump to the Catch clause. If no
+ such Throw is executed, then the assignment is not performed, and
+ the Catch clause is not executed.
+
+ The expression is not evaluated unless and until the exception is
+ caught, which is significant if it has side effects, for example:
+
+ Try foo();
+ Catch (p[++i].e) { ... }
+
+ IMPORTANT: Jumping into or out of a Try clause (for example via
+ return, break, continue, goto, longjmp) is forbidden--the compiler
+ will not complain, but bad things will happen at run-time. Jumping
+ into or out of a Catch clause is okay, and so is jumping around
+ inside a Try clause. In many cases where one is tempted to return
+ from a Try clause, it will suffice to use Throw, and then return
+ from the Catch clause. Another option is to set a flag variable and
+ use goto to jump to the end of the Try clause, then check the flag
+ after the Try/Catch statement.
+
+ IMPORTANT: The values of any non-volatile automatic variables
+ changed within the Try clause are undefined after an exception is
+ caught. Therefore, variables modified inside the Try block whose
+ values are needed later outside the Try block must either use static
+ storage or be declared with the "volatile" type qualifier.
+
+
+Throw expression;
+
+ A Throw statement is very much like a return statement, except that
+ the expression is required. Whereas return jumps back to the place
+ where the current function was called, Throw jumps back to the Catch
+ clause of the innermost enclosing Try clause. The expression must
+ be compatible with the type passed to define_exception_type(). The
+ exception must be caught, otherwise the program may crash.
+
+ Slight limitation: If the expression is a comma-expression it must
+ be enclosed in parentheses.
+
+
+Try statement
+Catch_anonymous statement
+
+ When the value of the exception is not needed, a Try/Catch statement
+ can use Catch_anonymous instead of Catch (expression).
+
+
+Everything below this point is for the benefit of the compiler. The
+application programmer should pretend not to know any of it, because it
+is subject to change.
+
+===*/
+
+
+#ifndef CEXCEPT_H
+#define CEXCEPT_H
+
+
+#include <setjmp.h>
+
+#define define_exception_type(etype) \
+struct exception_context { \
+ jmp_buf *penv; \
+ int caught; \
+ volatile struct { etype etmp; } v; \
+}
+
+/* etmp must be volatile because the application might use automatic */
+/* storage for the_exception_context, and etmp is modified between */
+/* the calls to setjmp() and longjmp(). A wrapper struct is used to */
+/* avoid warnings about a duplicate volatile qualifier in case etype */
+/* already includes it. */
+
+#define init_exception_context(ec) ((void)((ec)->penv = 0))
+
+#define Try \
+ { \
+ jmp_buf *exception__prev, exception__env; \
+ exception__prev = the_exception_context->penv; \
+ the_exception_context->penv = &exception__env; \
+ if (setjmp(exception__env) == 0) { \
+ if (&exception__prev)
+
+#define exception__catch(action) \
+ else { } \
+ the_exception_context->caught = 0; \
+ } \
+ else { \
+ the_exception_context->caught = 1; \
+ } \
+ the_exception_context->penv = exception__prev; \
+ } \
+ if (!the_exception_context->caught || action) { } \
+ else
+
+#define Catch(e) exception__catch(((e) = the_exception_context->v.etmp, 0))
+#define Catch_anonymous exception__catch(0)
+
+/* Try ends with if(), and Catch begins and ends with else. This */
+/* ensures that the Try/Catch syntax is really the same as the */
+/* if/else syntax. */
+/* */
+/* We use &exception__prev instead of 1 to appease compilers that */
+/* warn about constant expressions inside if(). Most compilers */
+/* should still recognize that &exception__prev is never zero and */
+/* avoid generating test code. */
+
+#define Throw \
+ for (;; longjmp(*the_exception_context->penv, 1)) \
+ the_exception_context->v.etmp =
+
+
+#endif /* CEXCEPT_H */
diff --git a/contrib/visupng/resource.h b/contrib/visupng/resource.h
new file mode 100644
index 0000000..611dd03
--- /dev/null
+++ b/contrib/visupng/resource.h
@@ -0,0 +1,23 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by VisualPng.rc
+//
+#define IDM_FILE_OPEN 40001
+#define IDM_FILE_SAVE 40002
+#define IDM_FILE_NEXT 40003
+#define IDM_FILE_PREVIOUS 40004
+#define IDM_FILE_EXIT 40005
+#define IDM_OPTIONS_BACKGROUND 40006
+#define IDM_OPTIONS_STRETCH 40007
+#define IDM_HELP_ABOUT 40008
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 113
+#define _APS_NEXT_COMMAND_VALUE 40009
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif