From 435ee8535cb55ef2488f2e35f4993926d75196c3 Mon Sep 17 00:00:00 2001 From: Peter Breitenlohner Date: Mon, 3 Jun 2013 07:19:49 +0000 Subject: libpng 1.6.2 git-svn-id: svn://tug.org/texlive/trunk@30821 c570f23f-e606-0410-a88d-b1316a301751 --- .../libs/libpng/libpng-1.6.2/contrib/README.txt | 4 + .../libpng-1.6.2/contrib/examples/README.txt | 24 + .../libpng-1.6.2/contrib/examples/iccfrompng.c | 180 + .../libpng-1.6.2/contrib/examples/pngpixel.c | 368 + .../libpng-1.6.2/contrib/examples/pngtopng.c | 92 + .../libpng/libpng-1.6.2/contrib/gregbook/COPYING | 340 + .../libpng/libpng-1.6.2/contrib/gregbook/LICENSE | 50 + .../libpng-1.6.2/contrib/gregbook/Makefile.mingw32 | 130 + .../libpng-1.6.2/contrib/gregbook/Makefile.sgi | 104 + .../libpng-1.6.2/contrib/gregbook/Makefile.unx | 132 + .../libpng-1.6.2/contrib/gregbook/Makefile.w32 | 113 + .../libpng/libpng-1.6.2/contrib/gregbook/README | 186 + .../libpng-1.6.2/contrib/gregbook/makevms.com | 132 + .../libpng/libpng-1.6.2/contrib/gregbook/readpng.c | 316 + .../libpng/libpng-1.6.2/contrib/gregbook/readpng.h | 88 + .../libpng-1.6.2/contrib/gregbook/readpng2.c | 505 + .../libpng-1.6.2/contrib/gregbook/readpng2.h | 116 + .../libpng/libpng-1.6.2/contrib/gregbook/readppm.c | 179 + .../libpng-1.6.2/contrib/gregbook/rpng-win.c | 728 ++ .../libpng/libpng-1.6.2/contrib/gregbook/rpng-x.c | 904 ++ .../libpng-1.6.2/contrib/gregbook/rpng2-win.c | 1253 +++ .../libpng/libpng-1.6.2/contrib/gregbook/rpng2-x.c | 2107 ++++ .../libpng-1.6.2/contrib/gregbook/toucan.png | Bin 0 -> 12901 bytes .../libpng/libpng-1.6.2/contrib/gregbook/wpng.c | 853 ++ .../libpng-1.6.2/contrib/gregbook/writepng.c | 401 + .../libpng-1.6.2/contrib/gregbook/writepng.h | 133 + .../libpng/libpng-1.6.2/contrib/libtests/fakepng.c | 57 + .../libpng-1.6.2/contrib/libtests/gentests.sh | 102 + .../libpng/libpng-1.6.2/contrib/libtests/makepng.c | 1486 +++ .../libpng-1.6.2/contrib/libtests/pngstest.c | 3742 +++++++ .../libpng-1.6.2/contrib/libtests/pngunknown.c | 1066 ++ .../libpng-1.6.2/contrib/libtests/pngvalid.c | 10145 +++++++++++++++++++ .../libpng/libpng-1.6.2/contrib/libtests/readpng.c | 104 + .../libpng/libpng-1.6.2/contrib/libtests/tarith.c | 999 ++ .../libpng/libpng-1.6.2/contrib/libtests/timepng.c | 303 + .../libpng/libpng-1.6.2/contrib/pngminim/README | 5 + .../libpng-1.6.2/contrib/pngminim/decoder/README | 10 + .../libpng-1.6.2/contrib/pngminim/decoder/makefile | 150 + .../contrib/pngminim/decoder/pngusr.dfa | 40 + .../libpng-1.6.2/contrib/pngminim/decoder/pngusr.h | 24 + .../libpng-1.6.2/contrib/pngminim/encoder/README | 10 + .../libpng-1.6.2/contrib/pngminim/encoder/makefile | 149 + .../contrib/pngminim/encoder/pngusr.dfa | 35 + .../libpng-1.6.2/contrib/pngminim/encoder/pngusr.h | 24 + .../libpng-1.6.2/contrib/pngminim/preader/README | 15 + .../libpng-1.6.2/contrib/pngminim/preader/makefile | 165 + .../contrib/pngminim/preader/pngusr.dfa | 40 + .../libpng-1.6.2/contrib/pngminim/preader/pngusr.h | 24 + .../libpng/libpng-1.6.2/contrib/pngminus/README | 153 + .../libpng-1.6.2/contrib/pngminus/makefile.std | 65 + .../libpng-1.6.2/contrib/pngminus/makefile.tc3 | 38 + .../libpng-1.6.2/contrib/pngminus/makevms.com | 92 + .../libpng-1.6.2/contrib/pngminus/png2pnm.bat | 41 + .../libpng/libpng-1.6.2/contrib/pngminus/png2pnm.c | 431 + .../libpng-1.6.2/contrib/pngminus/png2pnm.sh | 42 + .../libpng-1.6.2/contrib/pngminus/pngminus.bat | 4 + .../libpng-1.6.2/contrib/pngminus/pngminus.sh | 5 + .../libpng-1.6.2/contrib/pngminus/pnm2png.bat | 41 + .../libpng/libpng-1.6.2/contrib/pngminus/pnm2png.c | 549 + .../libpng-1.6.2/contrib/pngminus/pnm2png.sh | 42 + .../libpng/libpng-1.6.2/contrib/pngsuite/README | 105 + .../libpng-1.6.2/contrib/pngsuite/basn0g01.png | Bin 0 -> 164 bytes .../libpng-1.6.2/contrib/pngsuite/basn0g02.png | Bin 0 -> 104 bytes .../libpng-1.6.2/contrib/pngsuite/basn0g04.png | Bin 0 -> 145 bytes .../libpng-1.6.2/contrib/pngsuite/basn0g08.png | Bin 0 -> 138 bytes .../libpng-1.6.2/contrib/pngsuite/basn0g16.png | Bin 0 -> 167 bytes .../libpng-1.6.2/contrib/pngsuite/basn2c08.png | Bin 0 -> 145 bytes .../libpng-1.6.2/contrib/pngsuite/basn2c16.png | Bin 0 -> 302 bytes .../libpng-1.6.2/contrib/pngsuite/basn3p01.png | Bin 0 -> 112 bytes .../libpng-1.6.2/contrib/pngsuite/basn3p02.png | Bin 0 -> 146 bytes .../libpng-1.6.2/contrib/pngsuite/basn3p04.png | Bin 0 -> 216 bytes .../libpng-1.6.2/contrib/pngsuite/basn3p08.png | Bin 0 -> 1286 bytes .../libpng-1.6.2/contrib/pngsuite/basn4a08.png | Bin 0 -> 126 bytes .../libpng-1.6.2/contrib/pngsuite/basn4a16.png | Bin 0 -> 2206 bytes .../libpng-1.6.2/contrib/pngsuite/basn6a08.png | Bin 0 -> 184 bytes .../libpng-1.6.2/contrib/pngsuite/basn6a16.png | Bin 0 -> 3435 bytes .../libpng-1.6.2/contrib/pngsuite/ftbbn0g01.png | Bin 0 -> 176 bytes .../libpng-1.6.2/contrib/pngsuite/ftbbn0g02.png | Bin 0 -> 197 bytes .../libpng-1.6.2/contrib/pngsuite/ftbbn0g04.png | Bin 0 -> 429 bytes .../libpng-1.6.2/contrib/pngsuite/ftbbn2c16.png | Bin 0 -> 2041 bytes .../libpng-1.6.2/contrib/pngsuite/ftbbn3p08.png | Bin 0 -> 1499 bytes .../libpng-1.6.2/contrib/pngsuite/ftbgn2c16.png | Bin 0 -> 2041 bytes .../libpng-1.6.2/contrib/pngsuite/ftbgn3p08.png | Bin 0 -> 1499 bytes .../libpng-1.6.2/contrib/pngsuite/ftbrn2c08.png | Bin 0 -> 1633 bytes .../libpng-1.6.2/contrib/pngsuite/ftbwn0g16.png | Bin 0 -> 1313 bytes .../libpng-1.6.2/contrib/pngsuite/ftbwn3p08.png | Bin 0 -> 1496 bytes .../libpng-1.6.2/contrib/pngsuite/ftbyn3p08.png | Bin 0 -> 1499 bytes .../libpng-1.6.2/contrib/pngsuite/ftp0n0g08.png | Bin 0 -> 719 bytes .../libpng-1.6.2/contrib/pngsuite/ftp0n2c08.png | Bin 0 -> 1594 bytes .../libpng-1.6.2/contrib/pngsuite/ftp0n3p08.png | Bin 0 -> 1476 bytes .../libpng-1.6.2/contrib/pngsuite/ftp1n3p08.png | Bin 0 -> 1483 bytes .../libpng/libpng-1.6.2/contrib/tools/README.txt | 26 + .../libpng-1.6.2/contrib/tools/checksum-icc.c | 102 + .../libs/libpng/libpng-1.6.2/contrib/tools/chkfmt | 137 + .../libpng/libpng-1.6.2/contrib/tools/cvtcolor.c | 188 + .../libpng/libpng-1.6.2/contrib/tools/fixitxt.c | 144 + .../libpng/libpng-1.6.2/contrib/tools/intgamma.sh | 110 + .../libpng/libpng-1.6.2/contrib/tools/makesRGB.c | 430 + .../libs/libpng/libpng-1.6.2/contrib/tools/sRGB.h | 48 + .../libpng/libpng-1.6.2/contrib/visupng/PngFile.c | 451 + .../libpng/libpng-1.6.2/contrib/visupng/PngFile.h | 30 + .../libpng/libpng-1.6.2/contrib/visupng/README.txt | 61 + .../libpng-1.6.2/contrib/visupng/VisualPng.c | 970 ++ .../libpng-1.6.2/contrib/visupng/VisualPng.dsp | 147 + .../libpng-1.6.2/contrib/visupng/VisualPng.dsw | 29 + .../libpng-1.6.2/contrib/visupng/VisualPng.ico | Bin 0 -> 766 bytes .../libpng-1.6.2/contrib/visupng/VisualPng.png | Bin 0 -> 208 bytes .../libpng-1.6.2/contrib/visupng/VisualPng.rc | 152 + .../libpng/libpng-1.6.2/contrib/visupng/cexcept.h | 248 + .../libpng/libpng-1.6.2/contrib/visupng/resource.h | 23 + 110 files changed, 33037 insertions(+) create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/README.txt create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/examples/README.txt create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/examples/iccfrompng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/examples/pngpixel.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/examples/pngtopng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/COPYING create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/LICENSE create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.mingw32 create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.sgi create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.unx create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.w32 create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/README create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/makevms.com create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readppm.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng-win.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng-x.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-win.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-x.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/toucan.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/wpng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/writepng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/writepng.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/fakepng.c create mode 100755 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/gentests.sh create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/makepng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngstest.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngunknown.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngvalid.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/readpng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/tarith.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/timepng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/README create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/README create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/makefile create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.dfa create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/README create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/makefile create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.dfa create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/README create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/makefile create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.dfa create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/README create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makefile.std create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makefile.tc3 create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makevms.com create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.bat create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.sh create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.bat create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.sh create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.bat create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.sh create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/README create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g01.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g02.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g04.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g16.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c16.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p01.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p02.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p04.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a16.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a16.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g01.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g02.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g04.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn2c16.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn3p08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn2c16.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn3p08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbrn2c08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn0g16.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn3p08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbyn3p08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n0g08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n2c08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n3p08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp1n3p08.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/README.txt create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/checksum-icc.c create mode 100755 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/chkfmt create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/cvtcolor.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/fixitxt.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/intgamma.sh create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/makesRGB.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/tools/sRGB.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/README.txt create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.c create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.dsp create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.dsw create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.ico create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.png create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.rc create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/cexcept.h create mode 100644 Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/resource.h (limited to 'Build/source/libs/libpng/libpng-1.6.2/contrib') diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/README.txt b/Build/source/libs/libpng/libpng-1.6.2/contrib/README.txt new file mode 100644 index 00000000000..bcd433d3523 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/README.txt @@ -0,0 +1,4 @@ + +This "contrib" directory contains contributions which are not necessarily under +the libpng license, although all are open source. They are not part of +libpng proper and are not used for building the library. diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/examples/README.txt b/Build/source/libs/libpng/libpng-1.6.2/contrib/examples/README.txt new file mode 100644 index 00000000000..0525c9d36b4 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/examples/README.txt @@ -0,0 +1,24 @@ + +This directory (contrib/examples) contains examples of libpng usage. + +NO COPYRIGHT RIGHTS ARE CLAIMED TO ANY OF THE FILES IN THIS DIRECTORY. + +To the extent possible under law, the authors have waived all copyright and +related or neighboring rights to this work. This work is published from: +United States. + +The files may be used freely in any way. The intention is that appropriate +parts of the files be used in other libpng-using programs without any need for +the authors of the using code to seek copyright or license from the original +authors. + +The source code and comments in this directory are the original work of the +people named below. No other person or organization has made contributions to +the work in this directory. + +ORIGINAL AUTHORS + The following people have contributed to the code in this directory. None + of the people below claim any rights with regard to the contents of this + directory. + + John Bowler diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/examples/iccfrompng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/examples/iccfrompng.c new file mode 100644 index 00000000000..67676219e65 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/examples/iccfrompng.c @@ -0,0 +1,180 @@ +/*- iccfrompng + * + * COPYRIGHT: Written by John Cunningham Bowler, 2011. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Extract any icc profiles found in the given PNG files. This is a simple + * example of a program which extracts information from the header of a PNG file + * without processing the image. Notice that some header information may occur + * after the image data, textual data and comments are an example; the approach + * in this file won't work reliably for such data because it only looks for the + * information in the section of the file that preceeds the image data. + * + * Compile and link against libpng and zlib, plus anything else required on the + * system you use. + * + * To use supply a list of PNG files containing iCCP chunks, the chunks will be + * extracted to a similarly named file with the extension replaced by 'icc', + * which will be overwritten without warning. + */ +#include +#include +#include +#include + +#include + +static int verbose = 1; +static png_byte no_profile[] = "no profile"; + +static png_bytep +extract(FILE *fp, png_uint_32 *proflen) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); + png_infop info_ptr = NULL; + png_bytep result = NULL; + + /* Initialize for error or no profile: */ + *proflen = 0; + + if (png_ptr == NULL) + { + fprintf(stderr, "iccfrompng: version library mismatch?\n"); + return 0; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 0; + } + + png_init_io(png_ptr, fp); + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + png_read_info(png_ptr, info_ptr); + + { + png_charp name; + int compression_type; + png_bytep profile; + + if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile, + proflen) & PNG_INFO_iCCP) + { + result = malloc(*proflen); + if (result != NULL) + memcpy(result, profile, *proflen); + + else + png_error(png_ptr, "OOM allocating profile buffer"); + } + + else + result = no_profile; + } + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return result; +} + +static int +extract_one_file(const char *filename) +{ + int result = 0; + FILE *fp = fopen(filename, "rb"); + + if (fp != NULL) + { + png_uint_32 proflen = 0; + png_bytep profile = extract(fp, &proflen); + + if (profile != NULL && profile != no_profile) + { + size_t len; + char *output; + + { + const char *ep = strrchr(filename, '.'); + + if (ep != NULL) + len = ep-filename; + + else + len = strlen(filename); + } + + output = malloc(len + 5); + if (output != NULL) + { + FILE *of; + + memcpy(output, filename, len); + strcpy(output+len, ".icc"); + + of = fopen(output, "wb"); + if (of != NULL) + { + if (fwrite(profile, proflen, 1, of) == 1 && + fflush(of) == 0 && + fclose(of) == 0) + { + if (verbose) + printf("%s -> %s\n", filename, output); + /* Success return */ + result = 1; + } + + else + { + fprintf(stderr, "%s: error writing profile\n", output); + if (remove(output)) + fprintf(stderr, "%s: could not remove file\n", output); + } + } + + else + fprintf(stderr, "%s: failed to open output file\n", output); + + free(output); + } + + else + fprintf(stderr, "%s: OOM allocating string!\n", filename); + + free(profile); + } + + else if (verbose && profile == no_profile) + printf("%s has no profile\n", filename); + } + + else + fprintf(stderr, "%s: could not open file\n", filename); + + return result; +} + +int +main(int argc, char **argv) +{ + int i; + int extracted = 0; + + for (i=1; i +#include +#include /* required for error handling */ + +/* Normally use here to get the installed libpng, but this is done to + * ensure the code picks up the local libpng implementation: + */ +#include "../../png.h" + +/* Return component 'c' of pixel 'x' from the given row. */ +static unsigned int +component(png_const_bytep row, png_uint_32 x, unsigned int c, + unsigned int bit_depth, unsigned int channels) +{ + /* PNG images can be up to 2^31 pixels wide, but this means they can be up to + * 2^37 bits wide (for a 64-bit pixel - the largest possible) and hence 2^34 + * bytes wide. Since the row fitted into memory, however, the following must + * work: + */ + png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels); + png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c); + + row = (png_const_bytep)(((PNG_CONST png_byte (*)[8])row) + bit_offset_hi); + row += bit_offset_lo >> 3; + bit_offset_lo &= 0x07; + + /* PNG pixels are packed into bytes to put the first pixel in the highest + * bits of the byte and into two bytes for 16-bit values with the high 8 bits + * first, so: + */ + switch (bit_depth) + { + case 1: return (row[0] >> (7-bit_offset_lo)) & 0x01; + case 2: return (row[0] >> (6-bit_offset_lo)) & 0x03; + case 4: return (row[0] >> (4-bit_offset_lo)) & 0x0f; + case 8: return row[0]; + case 16: return (row[0] << 8) + row[1]; + default: + /* This should never happen, it indicates a bug in this program or in + * libpng itself: + */ + fprintf(stderr, "pngpixel: invalid bit depth %u\n", bit_depth); + exit(1); + } +} + +/* Print a pixel from a row returned by libpng; determine the row format, find + * the pixel, and print the relevant information to stdout. + */ +static void +print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row, + png_uint_32 x) +{ + PNG_CONST unsigned int bit_depth = png_get_bit_depth(png_ptr, info_ptr); + + switch (png_get_color_type(png_ptr, info_ptr)) + { + case PNG_COLOR_TYPE_GRAY: + printf("GRAY %u\n", component(row, x, 0, bit_depth, 1)); + return; + + /* The palette case is slightly more difficult - the palette and, if + * present, the tRNS ('transparency', though the values are really + * opacity) data must be read to give the full picture: + */ + case PNG_COLOR_TYPE_PALETTE: + { + PNG_CONST unsigned int index = component(row, x, 0, bit_depth, 1); + png_colorp palette = NULL; + int num_palette = 0; + + if ((png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) & + PNG_INFO_PLTE) && num_palette > 0 && palette != NULL) + { + png_bytep trans_alpha = NULL; + int num_trans = 0; + if ((png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, + NULL) & PNG_INFO_tRNS) && num_trans > 0 && + trans_alpha != NULL) + printf("INDEXED %u = %d %d %d %d\n", index, + palette[index].red, palette[index].green, + palette[index].blue, + index < num_trans ? trans_alpha[index] : 255); + + else /* no transparency */ + printf("INDEXED %u = %d %d %d\n", index, + palette[index].red, palette[index].green, + palette[index].blue); + } + + else + printf("INDEXED %u = invalid index\n", index); + } + return; + + case PNG_COLOR_TYPE_RGB: + printf("RGB %u %u %u\n", component(row, x, 0, bit_depth, 3), + component(row, x, 1, bit_depth, 3), + component(row, x, 2, bit_depth, 3)); + return; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + printf("GRAY+ALPHA %u %u\n", component(row, x, 0, bit_depth, 2), + component(row, x, 1, bit_depth, 2)); + return; + + case PNG_COLOR_TYPE_RGB_ALPHA: + printf("RGBA %u %u %u %u\n", component(row, x, 0, bit_depth, 4), + component(row, x, 1, bit_depth, 4), + component(row, x, 2, bit_depth, 4), + component(row, x, 3, bit_depth, 4)); + return; + + default: + png_error(png_ptr, "invalid color type"); + } +} + +int main(int argc, const char **argv) +{ + /* This program uses the default, based, libpng error handling + * mechanism, therefore any local variable that exists before the call to + * setjmp and is changed after the call to setjmp returns successfully must + * be declared with 'volatile' to ensure that their values don't get + * destroyed by longjmp: + */ + volatile int result = 1/*fail*/; + + if (argc == 4) + { + long x = atol(argv[1]); + long y = atol(argv[2]); + FILE *f = fopen(argv[3], "rb"); + volatile png_bytep row = NULL; + + if (f != NULL) + { + /* libpng requires a callback function for handling errors; this + * callback must not return. The default callback function uses a + * stored style jmp_buf which is held in a png_struct and + * writes error messages to stderr. Creating the png_struct is a + * little tricky; just copy the following code. + */ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + /* Declare stack variables to hold pointers to locally allocated + * data. + */ + + /* Initialize the error control buffer: */ + if (setjmp(png_jmpbuf(png_ptr)) == 0) + { + png_uint_32 width, height; + int bit_depth, color_type, interlace_method, + compression_method, filter_method; + png_bytep row_tmp; + + /* Now associate the recently opened (FILE*) with the default + * libpng initialization functions. Sometimes libpng is + * compiled without stdio support (it can be difficult to do + * in some environments); in that case you will have to write + * your own read callback to read data from the (FILE*). + */ + png_init_io(png_ptr, f); + + /* And read the first part of the PNG file - the header and + * all the information up to the first pixel. + */ + png_read_info(png_ptr, info_ptr); + + /* This fills in enough information to tell us the width of + * each row in bytes, allocate the appropriate amount of + * space. In this case png_malloc is used - it will not + * return if memory isn't available. + */ + row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, + info_ptr)); + + /* To avoid the overhead of using a volatile auto copy row_tmp + * to a local here - just use row for the png_free below. + */ + row_tmp = row; + + /* All the information we need is in the header is returned by + * png_get_IHDR, if this fails we can now use 'png_error' to + * signal the error and return control to the setjmp above. + */ + if (png_get_IHDR(png_ptr, info_ptr, &width, &height, + &bit_depth, &color_type, &interlace_method, + &compression_method, &filter_method)) + { + int passes, pass; + + /* png_set_interlace_handling returns the number of + * passes required as well as turning on libpng's + * handling, but since we do it ourselves this is + * necessary: + */ + switch (interlace_method) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "pngpixel: unknown interlace"); + } + + /* Now read the pixels, pass-by-pass, row-by-row: */ + png_start_read_image(png_ptr); + + for (pass=0; pass +#include +#include +#include + +/* Normally use here to get the installed libpng, but this is done to + * ensure the code picks up the local libpng implementation: + */ +#include "../../png.h" + +int main(int argc, const char **argv) +{ + int result = 1; + + if (argc == 3) + { + png_image image; + + /* Only the image structure version number needs to be set. */ + memset(&image, 0, sizeof image); + image.version = PNG_IMAGE_VERSION; + + if (png_image_begin_read_from_file(&image, argv[1])) + { + png_bytep buffer; + + /* Change this to try different formats! If you set a colormap format + * then you must also supply a colormap below. + */ + image.format = PNG_FORMAT_RGBA; + + buffer = malloc(PNG_IMAGE_SIZE(image)); + + if (buffer != NULL) + { + if (png_image_finish_read(&image, NULL/*background*/, buffer, + 0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */)) + { + if (png_image_write_to_file(&image, argv[2], + 0/*convert_to_8bit*/, buffer, 0/*row_stride*/, + NULL/*colormap*/)) + result = 0; + + else + fprintf(stderr, "pngtopng: write %s: %s\n", argv[2], + image.message); + + free(buffer); + } + + else + { + fprintf(stderr, "pngtopng: read %s: %s\n", argv[1], + image.message); + + /* This is the only place where a 'free' is required; libpng does + * the cleanup on error and success, but in this case we couldn't + * complete the read because of running out of memory. + */ + png_image_free(&image); + } + } + + else + fprintf(stderr, "pngtopng: out of memory: %lu bytes\n", + (unsigned long)PNG_IMAGE_SIZE(image)); + } + + else + /* Failed to read the first argument: */ + fprintf(stderr, "pngtopng: %s: %s\n", argv[1], image.message); + } + + else + /* Wrong number of arguments */ + fprintf(stderr, "pngtopng: usage: pngtopng input-file output-file\n"); + + return result; +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/COPYING b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/COPYING new file mode 100644 index 00000000000..a3e97747969 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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. + + + Copyright (C) + + 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. + + , 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/LICENSE b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/LICENSE new file mode 100644 index 00000000000..d9567178cb6 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.mingw32 b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.mingw32 new file mode 100644 index 00000000000..e70a59aef2b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.sgi b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.sgi new file mode 100644 index 00000000000..6c3bdf1919f --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/libpng16 +PNGLIB = -L/usr/local/lib -lpng16 # dynamically linked against libpng +#PNGLIB = /usr/local/lib/libpng16.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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.unx b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.unx new file mode 100644 index 00000000000..d5e4f355a92 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/libpng16 +#PNGLIBd = -L$(PNGDIR) -lpng16 # dynamically linked, installed libpng +#PNGLIBs = $(PNGDIR)/libpng16.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) -lpng16 # 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.w32 b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/Makefile.w32 new file mode 100644 index 00000000000..41cfb231a2c --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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 + + +# 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/README b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/README new file mode 100644 index 00000000000..7b1f6a3ea62 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/makevms.com b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/makevms.com new file mode 100644 index 00000000000..f32bcaba7f9 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng.c new file mode 100644 index 00000000000..f5e1fb1a4e2 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng.c @@ -0,0 +1,316 @@ +/*--------------------------------------------------------------------------- + + 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 +#include +#include + +#include "png.h" /* libpng header */ +#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_sig_cmp(sig, 0, 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))) { + free(image_data); + image_data = NULL; + free(row_pointers); + row_pointers = NULL; + 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); +#ifdef PNG_READ_16_TO_8_SUPPORTED + if (bit_depth == 16) +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +# else + png_set_strip_16(png_ptr); +# endif +#endif + 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng.h new file mode 100644 index 00000000000..fad9fe3b4c5 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.c new file mode 100644 index 00000000000..e179db71e63 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.c @@ -0,0 +1,505 @@ +/*--------------------------------------------------------------------------- + + 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 /* for exit() prototype */ +#include + +#include +#include "png.h" /* libpng header from the local directory */ +#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) +{ + fprintf(stderr, " Compiled with libpng %s; using libpng %s\n", + PNG_LIBPNG_VER_STRING, png_libpng_ver); + + fprintf(stderr, " and with zlib %s; using zlib %s.\n", + ZLIB_VERSION, zlib_version); +} + + + + +int readpng2_check_sig(uch *sig, int num) +{ + return !png_sig_cmp(sig, 0, 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_HANDLE_AS_UNKNOWN_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 version + * of readpng2.c recognizes more chunks, add them to this list. + */ + static PNG_CONST png_byte chunks_to_process[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 103, 65, 77, 65, '\0', /* gAMA */ + 115, 82, 71, 66, '\0', /* sRGB */ + }; + + /* Ignore all chunks except for IHDR, PLTE, tRNS, IDAT, and IEND */ + png_set_keep_unknown_chunks(png_ptr, -1 /* PNG_HANDLE_CHUNK_NEVER */, + NULL, -1); + + /* But do not ignore chunks in the "chunks_to_process" list */ + png_set_keep_unknown_chunks(png_ptr, + 0 /* PNG_HANDLE_CHUNK_AS_DEFAULT */, chunks_to_process, + sizeof(chunks_to_process)/5); + } +#endif /* PNG_HANDLE_AS_UNKNOWN_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); + + + /* 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; + png_uint_32 width, height; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double gamma; +#else + png_fixed_point gamma; +#endif + + + /* 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, &width, &height, &bit_depth, &color_type, + NULL, NULL, NULL); + mainprog_ptr->width = (ulg)width; + mainprog_ptr->height = (ulg)height; + + + /* 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); +#ifdef PNG_READ_16_TO_8_SUPPORTED + if (bit_depth == 16) +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +# else + png_set_strip_16(png_ptr); +# endif +#endif + 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. */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + 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); +#else + if (png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) + png_set_gamma_fixed(png_ptr, + (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), gamma); + else + png_set_gamma_fixed(png_ptr, + (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), 45455); +#endif + + /* 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); + } + + /* Now we have our data structure we can use the information in it + * to return control to our own higher level code (all the points + * where 'setjmp' is called in this file.) This will work with other + * error handling mechanisms as well - libpng always calls png_error + * when it can proceed no further, thus, so long as the error handler + * is intercepted, application code can do its own error recovery. + */ + longjmp(mainprog_ptr->jmpbuf, 1); +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.h new file mode 100644 index 00000000000..6b3660d7c17 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readpng2.h @@ -0,0 +1,116 @@ +/*--------------------------------------------------------------------------- + + 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; + 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readppm.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/readppm.c new file mode 100644 index 00000000000..be9a56d95fd --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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 +#include + +#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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng-win.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng-win.c new file mode 100644 index 00000000000..f53ddc8ece6 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng-win.c @@ -0,0 +1,728 @@ +/*--------------------------------------------------------------------------- + + 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 +#include +#include +#include +#include +#ifdef __CYGWIN__ +/* getch replacement. Turns out, we don't really need this, + * but leave it here if we ever enable any of the uses of + * _getch in the main code + */ +#include +#include +#include +int repl_getch( void ) +{ + char ch; + int fd = fileno(stdin); + struct termio old_tty, new_tty; + + ioctl(fd, TCGETA, &old_tty); + new_tty = old_tty; + new_tty.c_lflag &= ~(ICANON | ECHO | ISIG); + ioctl(fd, TCSETA, &new_tty); + fread(&ch, 1, sizeof(ch), stdin); + ioctl(fd, TCSETA, &old_tty); + + return ch; +} +#define _getch repl_getch +#else +#include /* only for _getch() */ +#endif + +/* #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; + +#ifndef __CYGWIN__ + /* 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); +#endif + + + /* 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) { +#ifndef __CYGWIN__ + int ch; +#endif + + 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" +#ifndef __CYGWIN__ + "Press Q or Esc to quit this usage screen.\n" +#endif + "\n", PROGNAME, default_display_exponent); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + 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) { +#ifndef __CYGWIN__ + int ch; +#endif + + fprintf(stderr, PROGNAME ": aborting.\n"); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + exit(2); + } else { + fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); +#ifndef __CYGWIN__ + fprintf(stderr, + "\n [console window: closing this window will terminate %s]\n\n", + PROGNAME); +#endif + } + + + /* 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( +#ifndef __CYGWIN__ + "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n" +#else + "Done. Press mouse button 1 (within image window) to quit.\n" +#endif + ); + 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng-x.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng-x.c new file mode 100644 index 00000000000..6d10e1b84ed --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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 +#include +#include +#include +#include +#include +#include +#include + +/* #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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-win.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-win.c new file mode 100644 index 00000000000..223e737409a --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-win.c @@ -0,0 +1,1253 @@ +/*--------------------------------------------------------------------------- + + 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 + - 2.03: removed runtime MMX-enabling/disabling and obsolete -mmx* options + + --------------------------------------------------------------------------- + + 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 +#include +#include +#include /* for jmpbuf declaration in readpng2.h */ +#include +#include /* only for PvdM background code */ +#include +#ifdef __CYGWIN__ +/* getch replacement. Turns out, we don't really need this, + * but leave it here if we ever enable any of the uses of + * _getch in the main code + */ +#include +#include +#include +int repl_getch( void ) +{ + char ch; + int fd = fileno(stdin); + struct termio old_tty, new_tty; + + ioctl(fd, TCGETA, &old_tty); + new_tty = old_tty; + new_tty.c_lflag &= ~(ICANON | ECHO | ISIG); + ioctl(fd, TCSETA, &new_tty); + fread(&ch, 1, sizeof(ch), stdin); + ioctl(fd, TCSETA, &old_tty); + + return ch; +} +#define _getch repl_getch +#else +#include /* only for _getch() */ +#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> 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)); + +#ifndef __CYGWIN__ + /* 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); +#endif + + /* 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; + } 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) { +#ifndef __CYGWIN__ + int ch; +#endif + + 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" + " %*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" + "\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n" +#ifndef __CYGWIN__ + "Press Q or Esc to quit this usage screen. ", +#else + , +#endif + PROGNAME, +#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \ + !(defined(__CYGWIN__) || defined(__MINGW32__)) + (int)strlen(PROGNAME), " ", +#endif + (int)strlen(PROGNAME), " ", default_display_exponent, num_bgpat); + fflush(stderr); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + 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) { +#ifndef __CYGWIN__ + int ch; +#endif + + fprintf(stderr, PROGNAME ": aborting.\n"); +#ifndef __CYGWIN__ + do + ch = _getch(); + while (ch != 'q' && ch != 'Q' && ch != 0x1B); +#endif + exit(2); + } else { + fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname); +#ifndef __CYGWIN__ + fprintf(stderr, + "\n [console window: closing this window will terminate %s]\n\n", + PROGNAME); +#endif + 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( +#ifndef __CYGWIN__ + "Done. Press Q, Esc or mouse button 1 (within image window) to quit.\n" +#else + "Done. Press mouse button 1 (within image window) to quit.\n" +#endif + ); + 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-x.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-x.c new file mode 100644 index 00000000000..7f24b632be0 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/rpng2-x.c @@ -0,0 +1,2107 @@ +/*--------------------------------------------------------------------------- + + 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 + - 2.03: deleted runtime MMX-enabling/disabling and obsolete -mmx* options + + --------------------------------------------------------------------------- + + 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.03 of 25 February 2010" +#define RESNAME "rpng2" /* our X resource application name */ +#define RESCLASS "Rpng" /* our X resource class name */ + +#include +#include +#include +#include +#include /* for jmpbuf declaration in readpng2.h */ +#include +#include /* only for PvdM background code */ +#include +#include +#include +#include /* defines XK_* macros */ + +#ifdef VMS +# include +#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> 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 + } 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" +#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 + " 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, + (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 call our error handler to 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/toucan.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/toucan.png new file mode 100644 index 00000000000..03960d49399 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/toucan.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/wpng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/wpng.c new file mode 100644 index 00000000000..a06e3529ecb --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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 +#include +#include +#include /* for jmpbuf declaration in writepng.h */ +#include + +#ifdef DOS_OS2_W32 +# include /* for isatty(), setmode() prototypes */ +# include /* 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 +# define getch() getkey() /* GRR: need getche() */ +# else +# include /* for getche() console input */ +# endif +# endif /* ?__EMX__ */ +# define FGETS(buf,len,stream) dos_kbd_gets(buf,len) +#else +# include /* 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 key.\n"); + /* note: just 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/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/writepng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/writepng.c new file mode 100644 index 00000000000..0dda62ea8c5 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/writepng.c @@ -0,0 +1,401 @@ +/*--------------------------------------------------------------------------- + + 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 /* for exit() prototype */ +#include + +#include "png.h" /* libpng header, includes 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 some other method to return control to + * application code, 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); + } + + /* Now we have our data structure we can use the information in it + * to return control to our own higher level code (all the points + * where 'setjmp' is called in this file.) This will work with other + * error handling mechanisms as well - libpng always calls png_error + * when it can proceed no further, thus, so long as the error handler + * is intercepted, application code can do its own error recovery. + */ + longjmp(mainprog_ptr->jmpbuf, 1); +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/writepng.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/gregbook/writepng.h new file mode 100644 index 00000000000..78b966b5874 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/fakepng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/fakepng.c new file mode 100644 index 00000000000..ba360d15a20 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/fakepng.c @@ -0,0 +1,57 @@ +/* Fake a PNG - just write it out directly. */ +#include +#include /* for crc32 */ + +void +put_uLong(uLong val) +{ + putchar(val >> 24); + putchar(val >> 16); + putchar(val >> 8); + putchar(val >> 0); +} + +void +put_chunk(const unsigned char *chunk, uInt length) +{ + uLong crc; + + put_uLong(length-4); /* Exclude the tag */ + + fwrite(chunk, length, 1, stdout); + + crc = crc32(0, Z_NULL, 0); + put_uLong(crc32(crc, chunk, length)); +} + +const unsigned char signature[] = +{ + 137, 80, 78, 71, 13, 10, 26, 10 +}; + +const unsigned char IHDR[] = +{ + 73, 72, 68, 82, /* IHDR */ + 0, 0, 0, 1, /* width */ + 0, 0, 0, 1, /* height */ + 1, /* bit depth */ + 0, /* color type: greyscale */ + 0, /* compression method */ + 0, /* filter method */ + 0 /* interlace method: none */ +}; + +const unsigned char unknown[] = +{ + 'u', 'n', 'K', 'n' /* "unKn" - private safe to copy */ +}; + +int +main(void) +{ + fwrite(signature, sizeof signature, 1, stdout); + put_chunk(IHDR, sizeof IHDR); + + for(;;) + put_chunk(unknown, sizeof unknown); +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/gentests.sh b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/gentests.sh new file mode 100755 index 00000000000..f0f8d2395a5 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/gentests.sh @@ -0,0 +1,102 @@ +#!/bin/sh +# +# Copyright (c) 2013 John Cunningham Bowler +# +# Last changed in libpng 1.6.0 [February 14, 2013] +# +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h +# +# Generate a set of PNG test images. The images are generated in a +# sub-directory called 'tests' by default, however a command line argument will +# change that name. The generation requires a built version of makepng in the +# current directory. +# +usage(){ + exec >&2 + echo "$0 []" + echo ' Generate a set of PNG test files in "directory" ("tests" by default)' + exit 1 +} + +mp="$PWD/makepng" +test -x "$mp" || { + exec >&2 + echo "$0: the 'makepng' program must exist" + echo " in the directory within which this program:" + echo " $mp" + echo " is executed" + usage +} + +# Just one argument: the directory +testdir="tests" +test $# -gt 1 && { + testdir="$1" + shift +} +test $# -eq 0 || usage + +# Take care not to clobber something +if test -e "$testdir" +then + test -d "$testdir" || usage +else + # mkdir -p isn't portable, so do the following + mkdir "$testdir" 2>/dev/null || mkdir -p "$testdir" || usage +fi + +# This fails in a very satisfactory way if it's not accessible +cd "$testdir" +:>"test$$.png" || { + exec >&2 + echo "$testdir: directory not writable" + usage +} +rm "test$$.png" || { + exec >&2 + echo "$testdir: you have create but not write privileges here." + echo " This is unexpected. You have a spurion; "'"'"test$$.png"'"'"." + echo " You need to remove this yourself. Try a different directory." + exit 1 +} + +# Now call makepng ($mp) to create every file we can think of with a +# reasonable name +doit(){ + for gamma in "" --sRGB --linear --1.8 + do + case "$gamma" in + "") + gname=;; + --sRGB) + gname="-srgb";; + --linear) + gname="-lin";; + --1.8) + gname="-18";; + *) + gname="-$gamma";; + esac + "$mp" $gamma "$1" "$2" "test-$1-$2$gname.png" + done +} +# +for ct in gray palette +do + for bd in 1 2 4 8 + do + doit "$ct" "$bd" + done +done +# +doit "gray" "16" +# +for ct in gray-alpha rgb rgb-alpha +do + for bd in 8 16 + do + doit "$ct" "$bd" + done +done diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/makepng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/makepng.c new file mode 100644 index 00000000000..9f11b29645b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/makepng.c @@ -0,0 +1,1486 @@ +/* makepng.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Make a test PNG image. The arguments are as follows: + * + * makepng [--sRGB|--linear|--1.8] [--color=] color-type bit-depth \ + * [file-name] + * + * The color-type may be numeric (and must match the numbers used by the PNG + * specification) or one of the format names listed below. The bit-depth is the + * component bit depth, or the pixel bit-depth for a color-mapped image. + * + * Without any options no color-space information is written, with the options + * an sRGB or the appropriate gAMA chunk is written. "1.8" refers to the + * display system used on older Apple computers to correct for high ambient + * light levels in the viewing environment; it applies a transform of + * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909 + * is written (1.45/2.2). + * + * The image data is generated internally. Unless --color is given the images + * used are as follows: + * + * 1 channel: a square image with a diamond, the least luminous colors are on + * the edge of the image, the most luminous in the center. + * + * 2 channels: the color channel increases in luminosity from top to bottom, the + * alpha channel increases in opacity from left to right. + * + * 3 channels: linear combinations of, from the top-left corner clockwise, + * black, green, white, red. + * + * 4 channels: linear combinations of, from the top-left corner clockwise, + * transparent, red, green, blue. + * + * For color-mapped images a four channel color-map is used and the PNG file has + * a tRNS chunk, as follows: + * + * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white + * 2-bit: entry 0: transparent-green + * entry 1: 40%-red + * entry 2: 80%-blue + * entry 3: opaque-white + * 4-bit: the 16 combinations of the 2-bit case + * 8-bit: the 256 combinations of the 4-bit case + * + * The palette always has 2^bit-depth entries and the tRNS chunk one fewer. The + * image is the 1-channel diamond, but using palette index, not luminosity. + * + * Image size is determined by the final pixel depth in bits, i.e. channels x + * bit-depth, as follows: + * + * 8 bits or less: 64x64 + * 16 bits: 256x256 + * More than 16 bits: 1024x1024 + * + * Row filtering is turned off (the 'none' filter is used on every row) and the + * images are not interlaced. + * + * If --color is given then the whole image has that color, color-mapped images + * will have exactly one palette entry and all image files with be 16x16 in + * size. The color value is 1 to 4 decimal numbers as appropriate for the color + * type. + * + * If file-name is given then the PNG is written to that file, else it is + * written to stdout. Notice that stdout is not supported on systems where, by + * default, it assumes text output; this program makes no attempt to change the + * text mode of stdout! + */ +#define _ISOC99_SOURCE /* for strtoull */ + +#include /* for offsetof */ +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +/* This structure is used for inserting extra chunks (the --insert argument, not + * documented above.) + */ +typedef struct chunk_insert +{ + struct chunk_insert *next; + void (*insert)(png_structp, png_infop, int, png_charpp); + int nparams; + png_charp parameters[1]; +} chunk_insert; + +static int +channels_of_type(int color_type) +{ + if (color_type & PNG_COLOR_MASK_PALETTE) + return 1; + + else + { + int channels = 1; + + if (color_type & PNG_COLOR_MASK_COLOR) + channels = 3; + + if (color_type & PNG_COLOR_MASK_ALPHA) + return channels + 1; + + else + return channels; + } +} + +static int +pixel_depth_of_type(int color_type, int bit_depth) +{ + return channels_of_type(color_type) * bit_depth; +} + +static unsigned int +image_size_of_type(int color_type, int bit_depth, unsigned int *colors) +{ + if (*colors) + return 16; + + else + { + int pixel_depth = pixel_depth_of_type(color_type, bit_depth); + + if (pixel_depth < 8) + return 64; + + else if (pixel_depth > 16) + return 1024; + + else + return 256; + } +} + +static void +set_color(png_colorp color, png_bytep trans, unsigned int red, + unsigned int green, unsigned int blue, unsigned int alpha, + png_const_bytep gamma_table) +{ + color->red = gamma_table[red]; + color->green = gamma_table[green]; + color->blue = gamma_table[blue]; + *trans = (png_byte)alpha; +} + +static int +generate_palette(png_colorp palette, png_bytep trans, int bit_depth, + png_const_bytep gamma_table, unsigned int *colors) +{ + /* + * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white + * 2-bit: entry 0: transparent-green + * entry 1: 40%-red + * entry 2: 80%-blue + * entry 3: opaque-white + * 4-bit: the 16 combinations of the 2-bit case + * 8-bit: the 256 combinations of the 4-bit case + */ + switch (colors[0]) + { + default: + fprintf(stderr, "makepng: --colors=...: invalid count %u\n", + colors[0]); + exit(1); + + case 1: + set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255, + gamma_table); + return 1; + + case 2: + set_color(palette+0, trans+0, colors[1], colors[1], colors[1], + colors[2], gamma_table); + return 1; + + case 3: + set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255, + gamma_table); + return 1; + + case 4: + set_color(palette+0, trans+0, colors[1], colors[2], colors[3], + colors[4], gamma_table); + return 1; + + case 0: + if (bit_depth == 1) + { + set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table); + set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table); + return 2; + } + + else + { + unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */ + unsigned int x, y, ip; + + for (x=0; x> 3; + + if (offset < rowbytes && (bit_depth < 16 || offset+1 < rowbytes)) + { + row += offset; + + switch (bit_depth) + { + case 1: + case 2: + case 4: + /* Don't gamma correct - values get smashed */ + { + unsigned int shift = (8 - bit_depth) - (x & 0x7U); + + mask <<= shift; + value = (value << shift) & mask; + *row = (png_byte)((*row & ~mask) | value); + } + return; + + default: + fprintf(stderr, "makepng: bad bit depth (internal error)\n"); + exit(1); + + case 16: + value = (unsigned int)floor(65535*pow(value/65535.,conv)+.5); + *row++ = (png_byte)(value >> 8); + *row = (png_byte)value; + return; + + case 8: + *row = gamma_table[value]; + return; + } + } + + else + { + fprintf(stderr, "makepng: row buffer overflow (internal error)\n"); + exit(1); + } + } + + else + { + fprintf(stderr, "makepng: component overflow (internal error)\n"); + exit(1); + } +} + +static void +generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type, + int bit_depth, png_const_bytep gamma_table, double conv, + unsigned int *colors) +{ + png_uint_32 size_max = image_size_of_type(color_type, bit_depth, colors)-1; + png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */ + + if (colors[0] == 0) switch (channels_of_type(color_type)) + { + /* 1 channel: a square image with a diamond, the least luminous colors are on + * the edge of the image, the most luminous in the center. + */ + case 1: + { + png_uint_32 x; + png_uint_32 base = 2*size_max - abs(2*y-size_max); + + for (x=0; x<=size_max; ++x) + { + png_uint_32 luma = base - abs(2*x-size_max); + + /* 'luma' is now in the range 0..2*size_max, we need + * 0..depth_max + */ + luma = (luma*depth_max + size_max) / (2*size_max); + set_value(row, rowbytes, x, bit_depth, luma, gamma_table, conv); + } + } + break; + + /* 2 channels: the color channel increases in luminosity from top to bottom, + * the alpha channel increases in opacity from left to right. + */ + case 2: + { + png_uint_32 alpha = (depth_max * y * 2 + size_max) / (2 * size_max); + png_uint_32 x; + + for (x=0; x<=size_max; ++x) + { + set_value(row, rowbytes, 2*x, bit_depth, + (depth_max * x * 2 + size_max) / (2 * size_max), gamma_table, + conv); + set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table, + conv); + } + } + break; + + /* 3 channels: linear combinations of, from the top-left corner clockwise, + * black, green, white, red. + */ + case 3: + { + /* x0: the black->red scale (the value of the red component) at the + * start of the row (blue and green are 0). + * x1: the green->white scale (the value of the red and blue + * components at the end of the row; green is depth_max). + */ + png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); + png_uint_32 x; + + /* Interpolate x/depth_max from start to end: + * + * start end difference + * red: Y Y 0 + * green: 0 depth_max depth_max + * blue: 0 Y Y + */ + for (x=0; x<=size_max; ++x) + { + set_value(row, rowbytes, 3*x+0, bit_depth, /* red */ Y, + gamma_table, conv); + set_value(row, rowbytes, 3*x+1, bit_depth, /* green */ + (depth_max * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 3*x+2, bit_depth, /* blue */ + (Y * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + } + } + break; + + /* 4 channels: linear combinations of, from the top-left corner clockwise, + * transparent, red, green, blue. + */ + case 4: + { + /* x0: the transparent->blue scale (the value of the blue and alpha + * components) at the start of the row (red and green are 0). + * x1: the red->green scale (the value of the red and green + * components at the end of the row; blue is 0 and alpha is + * depth_max). + */ + png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); + png_uint_32 x; + + /* Interpolate x/depth_max from start to end: + * + * start end difference + * red: 0 depth_max-Y depth_max-Y + * green: 0 Y Y + * blue: Y 0 -Y + * alpha: Y depth_max depth_max-Y + */ + for (x=0; x<=size_max; ++x) + { + set_value(row, rowbytes, 4*x+0, bit_depth, /* red */ + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 4*x+1, bit_depth, /* green */ + (Y * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 4*x+2, bit_depth, /* blue */ + Y - (Y * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + set_value(row, rowbytes, 4*x+3, bit_depth, /* alpha */ + Y + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), + gamma_table, conv); + } + } + break; + + default: + fprintf(stderr, "makepng: internal bad channel count\n"); + exit(2); + } + + else if (color_type & PNG_COLOR_MASK_PALETTE) + { + /* Palette with fixed color: the image rows are all 0 and the image width + * is 16. + */ + memset(row, 0, rowbytes); + } + + else if (colors[0] == channels_of_type(color_type)) + switch (channels_of_type(color_type)) + { + case 1: + { + const png_uint_32 luma = colors[1]; + png_uint_32 x; + + for (x=0; x<=size_max; ++x) + set_value(row, rowbytes, x, bit_depth, luma, gamma_table, + conv); + } + break; + + case 2: + { + const png_uint_32 luma = colors[1]; + const png_uint_32 alpha = colors[2]; + png_uint_32 x; + + for (x=0; x 0 && gamma < 1000) + gamma = PNG_FP_1; + + if (gamma > 0) + real_gamma = gamma; + + { + unsigned int i; + + if (real_gamma == 45455) for (i=0; i<256; ++i) + { + gamma_table[i] = (png_byte)i; + conv = 1.; + } + + else + { + /* Convert 'i' from sRGB (45455) to real_gamma, this makes + * the images look the same regardless of the gAMA chunk. + */ + conv = real_gamma; + conv /= 45455; + + gamma_table[0] = 0; + + for (i=1; i<255; ++i) + gamma_table[i] = (png_byte)floor(pow(i/255.,conv) * 255 + .5); + + gamma_table[255] = 255; + } + } + + png_set_IHDR(png_ptr, info_ptr, size, size, bit_depth, color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + if (color_type & PNG_COLOR_MASK_PALETTE) + { + int npalette; + png_color palette[256]; + png_byte trans[256]; + + npalette = generate_palette(palette, trans, bit_depth, gamma_table, + colors); + png_set_PLTE(png_ptr, info_ptr, palette, npalette); + png_set_tRNS(png_ptr, info_ptr, trans, npalette-1, + NULL/*transparent color*/); + + /* Reset gamma_table to prevent the image rows being changed */ + for (npalette=0; npalette<256; ++npalette) + gamma_table[npalette] = (png_byte)npalette; + } + + if (gamma == PNG_DEFAULT_sRGB) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); + + else if (gamma > 0) /* Else don't set color space information */ + { + png_set_gAMA_fixed(png_ptr, info_ptr, real_gamma); + + /* Just use the sRGB values here. */ + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + /* Insert extra information. */ + while (insert != NULL) + { + insert->insert(png_ptr, info_ptr, insert->nparams, insert->parameters); + insert = insert->next; + } + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Restrict the filters */ + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters); + + { + int passes = png_set_interlace_handling(png_ptr); + int pass; + png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + row = malloc(rowbytes); + + if (row == NULL) + png_error(png_ptr, "OOM allocating row buffer"); + + for (pass = 0; pass < passes; ++pass) + { + unsigned int y; + + for (y=0; y 0) + { + /* Round up to a multiple of 4 here to allow an iCCP profile + * to be padded to a 4x boundary. + */ + png_bytep data = malloc((total+3)&~3); + + if (data != NULL) + { + size_t new_size = 0; + + for (;;) + { + ch = getc(fp); + if (ch == EOF) break; + data[new_size++] = (png_byte)ch; + } + + if (ferror(fp) || new_size != total) + { + perror("temporary file"); + fprintf(stderr, "temporary file read error\n"); + free(data); + } + + else + { + (void)fclose(fp); + *result = data; + return total; + } + } + + else + fprintf(stderr, "%s: out of memory loading file\n", name); + } + + else + fprintf(stderr, "%s: empty file\n", name); + } + } + } + + else + { + perror(name); + fprintf(stderr, "%s: open failed\n", name); + } + + fclose(fp); + } + + else + fprintf(stderr, "makepng: %s: could not open temporary file\n", name); + + exit(1); + return 0; +} + +static png_size_t +load_fake(png_charp param, png_bytepp profile) +{ + char *endptr = NULL; + unsigned long long int size = strtoull(param, &endptr, 0/*base*/); + + /* The 'fake' format is *[string] */ + if (endptr != NULL && *endptr == '*') + { + size_t len = strlen(++endptr); + size_t result = (size_t)size; + + if (len == 0) len = 1; /* capture the terminating '\0' */ + + /* Now repeat that string to fill 'size' bytes. */ + if (result == size && (*profile = malloc(result)) != NULL) + { + png_bytep out = *profile; + + if (len == 1) + memset(out, *endptr, result); + + else + { + while (size >= len) + { + memcpy(out, endptr, len); + out += len; + size -= len; + } + memcpy(out, endptr, size); + } + + return result; + } + + else + { + fprintf(stderr, "%s: size exceeds system limits\n", param); + exit(1); + } + } + + return 0; +} + +static void +check_param_count(int nparams, int expect) +{ + if (nparams != expect) + { + fprintf(stderr, "bad parameter count (internal error)\n"); + exit(1); + } +} + +static void +insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_bytep profile = NULL; + png_uint_32 proflen = 0; + int result; + + check_param_count(nparams, 2); + + switch (params[1][0]) + { + case '<': + { + png_size_t filelen = load_file(params[1]+1, &profile); + if (filelen > 0xfffffffc) /* Maximum profile length */ + { + fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n", + params[1]+1, (unsigned long)filelen); + exit(1); + } + + proflen = (png_uint_32)filelen; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + png_size_t fake_len = load_fake(params[1], &profile); + + if (fake_len > 0) /* else a simple parameter */ + { + if (fake_len > 0xffffffff) /* Maximum profile length */ + { + fprintf(stderr, + "%s: fake data too long (%lu) for an ICC profile\n", + params[1], (unsigned long)fake_len); + exit(1); + } + proflen = (png_uint_32)(fake_len & ~3U); + /* Always fix up the profile length. */ + png_save_uint_32(profile, proflen); + break; + } + } + + default: + fprintf(stderr, "--insert iCCP \"%s\": unrecognized\n", params[1]); + fprintf(stderr, " use '<' to read a file: \" 3) + { + png_uint_32 prof_header = png_get_uint_32(profile); + + if (prof_header != proflen) + { + fprintf(stderr, "--insert iCCP %s: profile length field wrong:\n", + params[1]); + fprintf(stderr, " actual %lu, recorded value %lu (corrected)\n", + (unsigned long)proflen, (unsigned long)prof_header); + png_save_uint_32(profile, proflen); + } + } + + if (result && profile != NULL && proflen >=4) + png_set_iCCP(png_ptr, info_ptr, params[0], PNG_COMPRESSION_TYPE_BASE, + profile, proflen); + + if (profile) + free(profile); + + if (!result) + exit(1); +} + +static void +clear_text(png_text *text, png_charp keyword) +{ + text->compression = -1; /* none */ + text->key = keyword; + text->text = NULL; + text->text_length = 0; /* libpng calculates this */ + text->itxt_length = 0; /* libpng calculates this */ + text->lang = NULL; + text->lang_key = NULL; +} + +static void +set_text(png_structp png_ptr, png_infop info_ptr, png_textp text, + png_charp param) +{ + switch (param[0]) + { + case '<': + { + png_bytep file = NULL; + + text->text_length = load_file(param+1, &file); + text->text = (png_charp)file; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + png_bytep data = NULL; + png_size_t fake_len = load_fake(param, &data); + + if (fake_len > 0) /* else a simple parameter */ + { + text->text_length = fake_len; + text->text = (png_charp)data; + break; + } + } + + default: + text->text = param; + break; + } + + png_set_text(png_ptr, info_ptr, text, 1); + + if (text->text != param) + free(text->text); +} + +static void +insert_tEXt(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_text text; + + check_param_count(nparams, 2); + clear_text(&text, params[0]); + set_text(png_ptr, info_ptr, &text, params[1]); +} + +static void +insert_zTXt(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_text text; + + check_param_count(nparams, 2); + clear_text(&text, params[0]); + text.compression = 0; /* deflate */ + set_text(png_ptr, info_ptr, &text, params[1]); +} + +static void +insert_iTXt(png_structp png_ptr, png_infop info_ptr, int nparams, + png_charpp params) +{ + png_text text; + + check_param_count(nparams, 4); + clear_text(&text, params[0]); + text.compression = 2; /* iTXt + deflate */ + text.lang = params[1];/* language tag */ + text.lang_key = params[2]; /* translated keyword */ + set_text(png_ptr, info_ptr, &text, params[3]); +} + +static void +insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params) +{ + int i; + png_uint_16 freq[256]; + + /* libpng takes the count from the PLTE count; we don't check it here but we + * do set the array to 0 for unspecified entries. + */ + memset(freq, 0, sizeof freq); + for (i=0; inext = NULL; + cip->insert = insert; + cip->nparams = nparams; + for (i=0; iparameters[i] = list[i]; + + return cip; +} + +static chunk_insert * +find_insert(png_const_charp what, png_charp param) +{ + png_uint_32 chunk = 0; + png_charp parameter_list[1024]; + int i, nparams; + + /* Assemble the chunk name */ + for (i=0; i<4; ++i) + { + char ch = what[i]; + + if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) + chunk = (chunk << 8) + what[i]; + + else + break; + } + + if (i < 4 || what[4] != 0) + { + fprintf(stderr, "makepng --insert \"%s\": invalid chunk name\n", what); + exit(1); + } + + /* Assemble the parameter list. */ + nparams = find_parameters(what, param, parameter_list, 1024); + +# define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) + + switch (chunk) + { + case CHUNK(105,67,67,80): /* iCCP */ + if (nparams == 2) + return make_insert(what, insert_iCCP, nparams, parameter_list); + break; + + case CHUNK(116,69,88,116): /* tEXt */ + if (nparams == 2) + return make_insert(what, insert_tEXt, nparams, parameter_list); + break; + + case CHUNK(122,84,88,116): /* zTXt */ + if (nparams == 2) + return make_insert(what, insert_zTXt, nparams, parameter_list); + break; + + case CHUNK(105,84,88,116): /* iTXt */ + if (nparams == 4) + return make_insert(what, insert_iTXt, nparams, parameter_list); + break; + + case CHUNK(104,73,83,84): /* hIST */ + if (nparams <= 256) + return make_insert(what, insert_hIST, nparams, parameter_list); + break; + +#if 0 + case CHUNK(115,80,76,84): /* sPLT */ + return make_insert(what, insert_sPLT, nparams, parameter_list); +#endif + + default: + fprintf(stderr, "makepng --insert \"%s\": unrecognized chunk name\n", + what); + exit(1); + } + + bad_parameter_count(what, nparams); + return NULL; +} + +/* This is a not-very-good parser for a sequence of numbers (including 0). It + * doesn't accept some apparently valid things, but it accepts all the sensible + * combinations. + */ +static void +parse_color(char *arg, unsigned int *colors) +{ + unsigned int ncolors = 0; + + while (*arg && ncolors < 4) + { + char *ep = arg; + + unsigned long ul = strtoul(arg, &ep, 0); + + if (ul > 65535) + { + fprintf(stderr, "makepng --color=...'%s': too big\n", arg); + exit(1); + } + + if (ep == arg) + { + fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg); + exit(1); + } + + if (*ep) ++ep; /* skip a separator */ + arg = ep; + + colors[++ncolors] = (unsigned int)ul; /* checked above */ + } + + if (*arg) + { + fprintf(stderr, "makepng --color=...'%s': too many values\n", arg); + exit(1); + } + + *colors = ncolors; +} + +int +main(int argc, char **argv) +{ + FILE *fp = stdout; + const char *file_name = NULL; + int color_type = 8; /* invalid */ + int bit_depth = 32; /* invalid */ + unsigned int colors[5]; + unsigned int filters = PNG_ALL_FILTERS; + png_fixed_point gamma = 0; /* not set */ + chunk_insert *head_insert = NULL; + chunk_insert **insert_ptr = &head_insert; + + memset(colors, 0, sizeof colors); + + while (--argc > 0) + { + char *arg = *++argv; + + if (strcmp(arg, "--sRGB") == 0) + { + gamma = PNG_DEFAULT_sRGB; + continue; + } + + if (strcmp(arg, "--linear") == 0) + { + gamma = PNG_FP_1; + continue; + } + + if (strcmp(arg, "--1.8") == 0) + { + gamma = PNG_GAMMA_MAC_18; + continue; + } + + if (strcmp(arg, "--nofilters") == 0) + { + filters = PNG_FILTER_NONE; + continue; + } + + if (strncmp(arg, "--color=", 8) == 0) + { + parse_color(arg+8, colors); + continue; + } + + if (argc >= 3 && strcmp(arg, "--insert") == 0) + { + png_const_charp what = *++argv; + png_charp param = *++argv; + chunk_insert *new_insert; + + argc -= 2; + + new_insert = find_insert(what, param); + + if (new_insert != NULL) + { + *insert_ptr = new_insert; + insert_ptr = &new_insert->next; + } + + continue; + } + + if (arg[0] == '-') + { + fprintf(stderr, "makepng: %s: invalid option\n", arg); + exit(1); + } + + if (strcmp(arg, "palette") == 0) + { + color_type = PNG_COLOR_TYPE_PALETTE; + continue; + } + + if (strncmp(arg, "gray", 4) == 0) + { + if (arg[4] == 0) + { + color_type = PNG_COLOR_TYPE_GRAY; + continue; + } + + else if (strcmp(arg+4, "a") == 0 || + strcmp(arg+4, "alpha") == 0 || + strcmp(arg+4, "-alpha") == 0) + { + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + continue; + } + } + + if (strncmp(arg, "rgb", 3) == 0) + { + if (arg[3] == 0) + { + color_type = PNG_COLOR_TYPE_RGB; + continue; + } + + else if (strcmp(arg+3, "a") == 0 || + strcmp(arg+3, "alpha") == 0 || + strcmp(arg+3, "-alpha") == 0) + { + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + continue; + } + } + + if (color_type == 8 && isdigit(arg[0])) + { + color_type = atoi(arg); + if (color_type < 0 || color_type > 6 || color_type == 1 || + color_type == 5) + { + fprintf(stderr, "makepng: %s: not a valid color type\n", arg); + exit(1); + } + + continue; + } + + if (bit_depth == 32 && isdigit(arg[0])) + { + bit_depth = atoi(arg); + if (bit_depth <= 0 || bit_depth > 16 || + (bit_depth & -bit_depth) != bit_depth) + { + fprintf(stderr, "makepng: %s: not a valid bit depth\n", arg); + exit(1); + } + + continue; + } + + if (argc == 1) /* It's the file name */ + { + fp = fopen(arg, "wb"); + if (fp == NULL) + { + fprintf(stderr, "%s: %s: could not open\n", arg, strerror(errno)); + exit(1); + } + + file_name = arg; + continue; + } + + fprintf(stderr, "makepng: %s: unknown argument\n", arg); + exit(1); + } /* argument while loop */ + + if (color_type == 8 || bit_depth == 32) + { + fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] " + "[--color=...] color-type bit-depth [file-name]\n" + " Make a test PNG file, by default writes to stdout.\n"); + exit(1); + } + + /* Check the colors */ + { + const unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U : + (1U< lim) + { + fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n", + colors[i], lim); + exit(1); + } + } + + /* Restrict the filters for more speed to those we know are used for the + * generated images. + */ + if (filters == PNG_ALL_FILTERS) + { + if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8) + filters = PNG_FILTER_NONE; + + else if (color_type & PNG_COLOR_MASK_COLOR) /* rgb */ + { + if (bit_depth == 8) + filters &= ~(PNG_FILTER_NONE | PNG_FILTER_AVG); + + else + filters = PNG_FILTER_SUB | PNG_FILTER_PAETH; + } + + else /* gray 8 or 16-bit */ + filters &= ~PNG_FILTER_NONE; + } + + { + int ret = write_png(&file_name, fp, color_type, bit_depth, gamma, + head_insert, filters, colors); + + if (ret != 0 && file_name != NULL) + remove(file_name); + + return ret; + } +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngstest.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngstest.c new file mode 100644 index 00000000000..35e7c8779a2 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngstest.c @@ -0,0 +1,3742 @@ +/*- + * pngstest.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Test for the PNG 'simplified' APIs. + */ +#define _ISOC90_SOURCE 1 +#define MALLOC_CHECK_ 2/*glibc facility: turn on debugging*/ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* Else nothing can be done */ +#include "../tools/sRGB.h" + +/* KNOWN ISSUES + * + * These defines switch on alternate algorithms for format conversions to match + * the current libpng implementation; they are set to allow pngstest to pass + * even though libpng is producing answers that are not as correct as they + * should be. + */ +#define ALLOW_UNUSED_GPC 0 + /* If true include unused static GPC functions and declare an external array + * of them to hide the fact that they are unused. This is for development + * use while testing the correct function to use to take into account libpng + * misbehavior, such as using a simple power law to correct sRGB to linear. + */ + +/* The following is to support direct compilation of this file as C++ */ +#ifdef __cplusplus +# define voidcast(type, value) static_cast(value) +# define aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define voidcast(type, value) (value) +# define aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +/* During parallel runs of pngstest each temporary file needs a unique name, + * this is used to permit uniqueness using a command line argument which can be + * up to 22 characters long. + */ +static char tmpf[23] = "TMP"; + +/* Generate random bytes. This uses a boring repeatable algorithm and it + * is implemented here so that it gives the same set of numbers on every + * architecture. It's a linear congruential generator (Knuth or Sedgewick + * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and + * Hill, "The Art of Electronics". + */ +static void +make_random_bytes(png_uint_32* seed, void* pv, size_t size) +{ + png_uint_32 u0 = seed[0], u1 = seed[1]; + png_bytep bytes = voidcast(png_bytep, pv); + + /* There are thirty three bits, the next bit in the sequence is bit-33 XOR + * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. + */ + size_t i; + for (i=0; i> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; + u1 <<= 8; + u1 |= u0 >> 24; + u0 <<= 8; + u0 |= u; + *bytes++ = (png_byte)u; + } + + seed[0] = u0; + seed[1] = u1; +} + +static void +random_color(png_colorp color) +{ + static png_uint_32 color_seed[2] = { 0x12345678, 0x9abcdef }; + make_random_bytes(color_seed, color, sizeof *color); +} + +/* Math support - neither Cygwin nor Visual Studio have C99 support and we need + * a predictable rounding function, so make one here: + */ +static double +closestinteger(double x) +{ + return floor(x + .5); +} + +/* Cast support: remove GCC whines. */ +static png_byte +u8d(double d) +{ + d = closestinteger(d); + return (png_byte)d; +} + +static png_uint_16 +u16d(double d) +{ + d = closestinteger(d); + return (png_uint_16)d; +} + +/* sRGB support: use exact calculations rounded to the nearest int, see the + * fesetround() call in main(). sRGB_to_d optimizes the 8 to 16-bit conversion. + */ +static double sRGB_to_d[256]; +static double g22_to_d[256]; + +static void +init_sRGB_to_d(void) +{ + int i; + + sRGB_to_d[0] = 0; + for (i=1; i<255; ++i) + sRGB_to_d[i] = linear_from_sRGB(i/255.); + sRGB_to_d[255] = 1; + + g22_to_d[0] = 0; + for (i=1; i<255; ++i) + g22_to_d[i] = pow(i/255., 1/.45455); + g22_to_d[255] = 1; +} + +static png_byte +sRGB(double linear /*range 0.0 .. 1.0*/) +{ + return u8d(255 * sRGB_from_linear(linear)); +} + +static png_byte +isRGB(int fixed_linear) +{ + return sRGB(fixed_linear / 65535.); +} + +#if 0 /* not used */ +static png_byte +unpremultiply(int component, int alpha) +{ + if (alpha <= component) + return 255; /* Arbitrary, but consistent with the libpng code */ + + else if (alpha >= 65535) + return isRGB(component); + + else + return sRGB((double)component / alpha); +} +#endif + +static png_uint_16 +ilinear(int fixed_srgb) +{ + return u16d(65535 * sRGB_to_d[fixed_srgb]); +} + +static png_uint_16 +ilineara(int fixed_srgb, int alpha) +{ + return u16d((257 * alpha) * sRGB_to_d[fixed_srgb]); +} + +static png_uint_16 +ilinear_g22(int fixed_srgb) +{ + return u16d(65535 * g22_to_d[fixed_srgb]); +} + +#if ALLOW_UNUSED_GPC +static png_uint_16 +ilineara_g22(int fixed_srgb, int alpha) +{ + return u16d((257 * alpha) * g22_to_d[fixed_srgb]); +} +#endif + +static double +YfromRGBint(int ir, int ig, int ib) +{ + double r = ir; + double g = ig; + double b = ib; + return YfromRGB(r, g, b); +} + +#if 0 /* unused */ +/* The error that results from using a 2.2 power law in place of the correct + * sRGB transform, given an 8-bit value which might be either sRGB or power-law. + */ +static int +power_law_error8(int value) +{ + if (value > 0 && value < 255) + { + double vd = value / 255.; + double e = fabs( + pow(sRGB_to_d[value], 1/2.2) - sRGB_from_linear(pow(vd, 2.2))); + + /* Always allow an extra 1 here for rounding errors */ + e = 1+floor(255 * e); + return (int)e; + } + + return 0; +} + +static int error_in_sRGB_roundtrip = 56; /* by experiment */ +static int +power_law_error16(int value) +{ + if (value > 0 && value < 65535) + { + /* Round trip the value through an 8-bit representation but using + * non-matching to/from conversions. + */ + double vd = value / 65535.; + double e = fabs( + pow(sRGB_from_linear(vd), 2.2) - linear_from_sRGB(pow(vd, 1/2.2))); + + /* Always allow an extra 1 here for rounding errors */ + e = error_in_sRGB_roundtrip+floor(65535 * e); + return (int)e; + } + + return 0; +} + +static int +compare_8bit(int v1, int v2, int error_limit, int multiple_algorithms) +{ + int e = abs(v1-v2); + int ev1, ev2; + + if (e <= error_limit) + return 1; + + if (!multiple_algorithms) + return 0; + + ev1 = power_law_error8(v1); + if (e <= ev1) + return 1; + + ev2 = power_law_error8(v2); + if (e <= ev2) + return 1; + + return 0; +} + +static int +compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) +{ + int e = abs(v1-v2); + int ev1, ev2; + + if (e <= error_limit) + return 1; + + /* "multiple_algorithms" in this case means that a color-map has been + * involved somewhere, so we can deduce that the values were forced to 8-bit + * (like the via_linear case for 8-bit.) + */ + if (!multiple_algorithms) + return 0; + + ev1 = power_law_error16(v1); + if (e <= ev1) + return 1; + + ev2 = power_law_error16(v2); + if (e <= ev2) + return 1; + + return 0; +} +#endif /* unused */ + +#define READ_FILE 1 /* else memory */ +#define USE_STDIO 2 /* else use file name */ +#define STRICT 4 /* fail on warnings too */ +#define VERBOSE 8 +#define KEEP_TMPFILES 16 /* else delete temporary files */ +#define KEEP_GOING 32 +#define ACCUMULATE 64 +#define FAST_WRITE 128 +#define sRGB_16BIT 256 + +static void +print_opts(png_uint_32 opts) +{ + if (opts & READ_FILE) + printf(" --file"); + if (opts & USE_STDIO) + printf(" --stdio"); + if (opts & STRICT) + printf(" --strict"); + if (opts & VERBOSE) + printf(" --verbose"); + if (opts & KEEP_TMPFILES) + printf(" --preserve"); + if (opts & KEEP_GOING) + printf(" --keep-going"); + if (opts & ACCUMULATE) + printf(" --accumulate"); + if (!(opts & FAST_WRITE)) /* --fast is currently the default */ + printf(" --slow"); + if (opts & sRGB_16BIT) + printf(" --sRGB-16bit"); +} + +#define FORMAT_NO_CHANGE 0x80000000 /* additional flag */ + +/* A name table for all the formats - defines the format of the '+' arguments to + * pngstest. + */ +#define FORMAT_COUNT 64 +#define FORMAT_MASK 0x3f +static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = +{ + "sRGB-gray", + "sRGB-gray+alpha", + "sRGB-rgb", + "sRGB-rgb+alpha", + "linear-gray", + "linear-gray+alpha", + "linear-rgb", + "linear-rgb+alpha", + + "color-mapped-sRGB-gray", + "color-mapped-sRGB-gray+alpha", + "color-mapped-sRGB-rgb", + "color-mapped-sRGB-rgb+alpha", + "color-mapped-linear-gray", + "color-mapped-linear-gray+alpha", + "color-mapped-linear-rgb", + "color-mapped-linear-rgb+alpha", + + "sRGB-gray", + "sRGB-gray+alpha", + "sRGB-bgr", + "sRGB-bgr+alpha", + "linear-gray", + "linear-gray+alpha", + "linear-bgr", + "linear-bgr+alpha", + + "color-mapped-sRGB-gray", + "color-mapped-sRGB-gray+alpha", + "color-mapped-sRGB-bgr", + "color-mapped-sRGB-bgr+alpha", + "color-mapped-linear-gray", + "color-mapped-linear-gray+alpha", + "color-mapped-linear-bgr", + "color-mapped-linear-bgr+alpha", + + "sRGB-gray", + "alpha+sRGB-gray", + "sRGB-rgb", + "alpha+sRGB-rgb", + "linear-gray", + "alpha+linear-gray", + "linear-rgb", + "alpha+linear-rgb", + + "color-mapped-sRGB-gray", + "color-mapped-alpha+sRGB-gray", + "color-mapped-sRGB-rgb", + "color-mapped-alpha+sRGB-rgb", + "color-mapped-linear-gray", + "color-mapped-alpha+linear-gray", + "color-mapped-linear-rgb", + "color-mapped-alpha+linear-rgb", + + "sRGB-gray", + "alpha+sRGB-gray", + "sRGB-bgr", + "alpha+sRGB-bgr", + "linear-gray", + "alpha+linear-gray", + "linear-bgr", + "alpha+linear-bgr", + + "color-mapped-sRGB-gray", + "color-mapped-alpha+sRGB-gray", + "color-mapped-sRGB-bgr", + "color-mapped-alpha+sRGB-bgr", + "color-mapped-linear-gray", + "color-mapped-alpha+linear-gray", + "color-mapped-linear-bgr", + "color-mapped-alpha+linear-bgr", +}; + +/* Decode an argument to a format number. */ +static png_uint_32 +formatof(const char *arg) +{ + char *ep; + unsigned long format = strtoul(arg, &ep, 0); + + if (ep > arg && *ep == 0 && format < FORMAT_COUNT) + return (png_uint_32)format; + + else for (format=0; format < FORMAT_COUNT; ++format) + { + if (strcmp(format_names[format], arg) == 0) + return (png_uint_32)format; + } + + fprintf(stderr, "pngstest: format name '%s' invalid\n", arg); + return FORMAT_COUNT; +} + +/* Bitset/test functions for formats */ +#define FORMAT_SET_COUNT (FORMAT_COUNT / 32) +typedef struct +{ + png_uint_32 bits[FORMAT_SET_COUNT]; +} +format_list; + +static void format_init(format_list *pf) +{ + int i; + for (i=0; ibits[i] = 0; /* All off */ +} + +#if 0 /* currently unused */ +static void format_clear(format_list *pf) +{ + int i; + for (i=0; ibits[i] = 0; +} +#endif + +static int format_is_initial(format_list *pf) +{ + int i; + for (i=0; ibits[i] != 0) + return 0; + + return 1; +} + +static int format_set(format_list *pf, png_uint_32 format) +{ + if (format < FORMAT_COUNT) + return pf->bits[format >> 5] |= ((png_uint_32)1) << (format & 31); + + return 0; +} + +#if 0 /* currently unused */ +static int format_unset(format_list *pf, png_uint_32 format) +{ + if (format < FORMAT_COUNT) + return pf->bits[format >> 5] &= ~((png_uint_32)1) << (format & 31); + + return 0; +} +#endif + +static int format_isset(format_list *pf, png_uint_32 format) +{ + return format < FORMAT_COUNT && + (pf->bits[format >> 5] & (((png_uint_32)1) << (format & 31))) != 0; +} + +static void format_default(format_list *pf, int redundant) +{ + if (redundant) + { + int i; + + /* set everything, including flags that are pointless */ + for (i=0; ibits[i] = ~(png_uint_32)0; + } + + else + { + png_uint_32 f; + + for (f=0; finput_file != NULL) + rewind(image->input_file); +} + +/* Free the image buffer; the buffer is re-used on a re-read, this is just for + * cleanup. + */ +static void +freebuffer(Image *image) +{ + if (image->buffer) free(image->buffer); + image->buffer = NULL; + image->bufsize = 0; + image->allocsize = 0; +} + +/* Delete function; cleans out all the allocated data and the temporary file in + * the image. + */ +static void +freeimage(Image *image) +{ + freebuffer(image); + png_image_free(&image->image); + + if (image->input_file != NULL) + { + fclose(image->input_file); + image->input_file = NULL; + } + + if (image->input_memory != NULL) + { + free(image->input_memory); + image->input_memory = NULL; + image->input_memory_size = 0; + } + + if (image->tmpfile_name[0] != 0 && (image->opts & KEEP_TMPFILES) == 0) + { + remove(image->tmpfile_name); + image->tmpfile_name[0] = 0; + } +} + +/* This is actually a re-initializer; allows an image structure to be re-used by + * freeing everything that relates to an old image. + */ +static void initimage(Image *image, png_uint_32 opts, const char *file_name, + int stride_extra) +{ + freeimage(image); + memset(&image->image, 0, sizeof image->image); + image->opts = opts; + image->file_name = file_name; + image->stride_extra = stride_extra; +} + +/* Make sure the image buffer is big enough; allows re-use of the buffer if the + * image is re-read. + */ +#define BUFFER_INIT8 73 +static void +allocbuffer(Image *image) +{ + png_size_t size = PNG_IMAGE_BUFFER_SIZE(image->image, image->stride); + + if (size+32 > image->bufsize) + { + freebuffer(image); + image->buffer = voidcast(png_bytep, malloc(size+32)); + if (image->buffer == NULL) + { + fflush(stdout); + fprintf(stderr, + "simpletest: out of memory allocating %lu(+32) byte buffer\n", + (unsigned long)size); + exit(1); + } + image->bufsize = size+32; + } + + memset(image->buffer, 95, image->bufsize); + memset(image->buffer+16, BUFFER_INIT8, size); + image->allocsize = size; +} + +/* Make sure 16 bytes match the given byte. */ +static int +check16(png_const_bytep bp, int b) +{ + int i = 16; + + do + if (*bp != b) return 1; + while (--i); + + return 0; +} + +/* Check for overwrite in the image buffer. */ +static void +checkbuffer(Image *image, const char *arg) +{ + if (check16(image->buffer, 95)) + { + fflush(stdout); + fprintf(stderr, "%s: overwrite at start of image buffer\n", arg); + exit(1); + } + + if (check16(image->buffer+16+image->allocsize, 95)) + { + fflush(stdout); + fprintf(stderr, "%s: overwrite at end of image buffer\n", arg); + exit(1); + } +} + +/* ERROR HANDLING */ +/* Log a terminal error, also frees the libpng part of the image if necessary. + */ +static int +logerror(Image *image, const char *a1, const char *a2, const char *a3) +{ + fflush(stdout); + if (image->image.warning_or_error) + fprintf(stderr, "%s%s%s: %s\n", a1, a2, a3, image->image.message); + + else + fprintf(stderr, "%s%s%s\n", a1, a2, a3); + + if (image->image.opaque != NULL) + { + fprintf(stderr, "%s: image opaque pointer non-NULL on error\n", + image->file_name); + png_image_free(&image->image); + } + + return 0; +} + +/* Log an error and close a file (just a utility to do both things in one + * function call.) + */ +static int +logclose(Image *image, FILE *f, const char *name, const char *operation) +{ + int e = errno; + + fclose(f); + return logerror(image, name, operation, strerror(e)); +} + +/* Make sure the png_image has been freed - validates that libpng is doing what + * the spec says and freeing the image. + */ +static int +checkopaque(Image *image) +{ + if (image->image.opaque != NULL) + { + png_image_free(&image->image); + return logerror(image, image->file_name, ": opaque not NULL", ""); + } + + else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0) + return logerror(image, image->file_name, " --strict", ""); + + else + return 1; +} + +/* IMAGE COMPARISON/CHECKING */ +/* Compare the pixels of two images, which should be the same but aren't. The + * images must have been checked for a size match. + */ +typedef struct +{ + /* The components, for grayscale images the gray value is in 'g' and if alpha + * is not present 'a' is set to 255 or 65535 according to format. + */ + int r, g, b, a; +} Pixel; + +typedef struct +{ + /* The background as the original sRGB 8-bit value converted to the final + * integer format and as a double precision linear value in the range 0..1 + * for with partially transparent pixels. + */ + int ir, ig, ib; + double dr, dg, db; /* linear r,g,b scaled to 0..1 */ +} Background; + +/* Basic image formats; control the data but not the layout thereof. */ +#define BASE_FORMATS\ + (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_LINEAR) + +/* Read a Pixel from a buffer. The code below stores the correct routine for + * the format in a function pointer, these are the routines: + */ +static void +gp_g8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = p->g = p->b = pp[0]; + p->a = 255; +} + +static void +gp_ga8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = p->g = p->b = pp[0]; + p->a = pp[1]; +} + +static void +gp_ag8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = p->g = p->b = pp[1]; + p->a = pp[0]; +} + +static void +gp_rgb8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = 255; +} + +static void +gp_bgr8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = 255; +} + +static void +gp_rgba8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = pp[3]; +} + +static void +gp_bgra8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = pp[3]; +} + +static void +gp_argb8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[1]; + p->g = pp[2]; + p->b = pp[3]; + p->a = pp[0]; +} + +static void +gp_abgr8(Pixel *p, png_const_voidp pb) +{ + png_const_bytep pp = voidcast(png_const_bytep, pb); + + p->r = pp[3]; + p->g = pp[2]; + p->b = pp[1]; + p->a = pp[0]; +} + +static void +gp_g16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = p->g = p->b = pp[0]; + p->a = 65535; +} + +static void +gp_ga16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = p->g = p->b = pp[0]; + p->a = pp[1]; +} + +static void +gp_ag16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = p->g = p->b = pp[1]; + p->a = pp[0]; +} + +static void +gp_rgb16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = 65535; +} + +static void +gp_bgr16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = 65535; +} + +static void +gp_rgba16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[0]; + p->g = pp[1]; + p->b = pp[2]; + p->a = pp[3]; +} + +static void +gp_bgra16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[2]; + p->g = pp[1]; + p->b = pp[0]; + p->a = pp[3]; +} + +static void +gp_argb16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[1]; + p->g = pp[2]; + p->b = pp[3]; + p->a = pp[0]; +} + +static void +gp_abgr16(Pixel *p, png_const_voidp pb) +{ + png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + + p->r = pp[3]; + p->g = pp[2]; + p->b = pp[1]; + p->a = pp[0]; +} + +/* Given a format, return the correct one of the above functions. */ +static void (* +get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb) +{ + /* The color-map flag is irrelevant here - the caller of the function + * returned must either pass the buffer or, for a color-mapped image, the + * correct entry in the color-map. + */ + if (format & PNG_FORMAT_FLAG_LINEAR) + { + if (format & PNG_FORMAT_FLAG_COLOR) + { + if (format & PNG_FORMAT_FLAG_BGR) + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_abgr16; + + else + return gp_bgra16; + } + + else + return gp_bgr16; + } + + else + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_argb16; + + else + return gp_rgba16; + } + + else + return gp_rgb16; + } + } + + else + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_ag16; + + else + return gp_ga16; + } + + else + return gp_g16; + } + } + + else + { + if (format & PNG_FORMAT_FLAG_COLOR) + { + if (format & PNG_FORMAT_FLAG_BGR) + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_abgr8; + + else + return gp_bgra8; + } + + else + return gp_bgr8; + } + + else + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_argb8; + + else + return gp_rgba8; + } + + else + return gp_rgb8; + } + } + + else + { + if (format & PNG_FORMAT_FLAG_ALPHA) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + return gp_ag8; + + else + return gp_ga8; + } + + else + return gp_g8; + } + } +} + +/* Convertion between pixel formats. The code above effectively eliminates the + * component ordering changes leaving three basic changes: + * + * 1) Remove an alpha channel by pre-multiplication or compositing on a + * background color. (Adding an alpha channel is a no-op.) + * + * 2) Remove color by mapping to grayscale. (Grayscale to color is a no-op.) + * + * 3) Convert between 8-bit and 16-bit components. (Both directtions are + * relevant.) + * + * This gives the following base format conversion matrix: + * + * OUT: ----- 8-bit ----- ----- 16-bit ----- + * IN G GA RGB RGBA G GA RGB RGBA + * 8 G . . . . lin lin lin lin + * 8 GA bckg . bckc . pre' pre pre' pre + * 8 RGB g8 g8 . . glin glin lin lin + * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre + * 16 G sRGB sRGB sRGB sRGB . . . . + * 16 GA b16g unpg b16c unpc A . A . + * 16 RGB sG sG sRGB sRGB g16 g16 . . + * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . + * + * 8-bit to 8-bit: + * bckg: composite on gray background + * bckc: composite on color background + * g8: convert sRGB components to sRGB grayscale + * g8b: convert sRGB components to grayscale and composite on gray background + * + * 8-bit to 16-bit: + * lin: make sRGB components linear, alpha := 65535 + * pre: make sRGB components linear and premultiply by alpha (scale alpha) + * pre': as 'pre' but alpha := 65535 + * glin: make sRGB components linear, convert to grayscale, alpha := 65535 + * gpre: make sRGB components grayscale and linear and premultiply by alpha + * gpr': as 'gpre' but alpha := 65535 + * + * 16-bit to 8-bit: + * sRGB: convert linear components to sRGB, alpha := 255 + * unpg: unpremultiply gray component and convert to sRGB (scale alpha) + * unpc: unpremultiply color components and convert to sRGB (scale alpha) + * b16g: composite linear onto gray background and convert the result to sRGB + * b16c: composite linear onto color background and convert the result to sRGB + * sG: convert linear RGB to sRGB grayscale + * sGp: unpremultiply RGB then convert to sRGB grayscale + * sCp: unpremultiply RGB then convert to sRGB + * gb16: composite linear onto background and convert to sRGB grayscale + * (order doesn't matter, the composite and grayscale operations permute) + * cb16: composite linear onto background and convert to sRGB + * + * 16-bit to 16-bit: + * A: set alpha to 65535 + * g16: convert linear RGB to linear grayscale (alpha := 65535) + * g16': as 'g16' but alpha is unchanged + */ +/* Simple copy: */ +static void +gpc_noop(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = in->r; + out->g = in->g; + out->b = in->b; + out->a = in->a; +} + +#if ALLOW_UNUSED_GPC +static void +gpc_nop8(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + if (in->a == 0) + out->r = out->g = out->b = 255; + + else + { + out->r = in->r; + out->g = in->g; + out->b = in->b; + } + + out->a = in->a; +} +#endif + +#if ALLOW_UNUSED_GPC +static void +gpc_nop6(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + if (in->a == 0) + out->r = out->g = out->b = 65535; + + else + { + out->r = in->r; + out->g = in->g; + out->b = in->b; + } + + out->a = in->a; +} +#endif + +/* 8-bit to 8-bit conversions */ +/* bckg: composite on gray background */ +static void +gpc_bckg(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else if (in->a >= 255) + out->r = out->g = out->b = in->g; + + else + { + double a = in->a / 255.; + + out->r = out->g = out->b = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); + } + + out->a = 255; +} + +/* bckc: composite on color background */ +static void +gpc_bckc(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + { + out->r = back->ir; + out->g = back->ig; + out->b = back->ib; + } + + else if (in->a >= 255) + { + out->r = in->r; + out->g = in->g; + out->b = in->b; + } + + else + { + double a = in->a / 255.; + + out->r = sRGB(sRGB_to_d[in->r] * a + back->dr * (1-a)); + out->g = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); + out->b = sRGB(sRGB_to_d[in->b] * a + back->db * (1-a)); + } + + out->a = 255; +} + +/* g8: convert sRGB components to sRGB grayscale */ +static void +gpc_g8(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = in->g; + + else + out->r = out->g = out->b = + sRGB(YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = in->a; +} + +/* g8b: convert sRGB components to grayscale and composite on gray background */ +static void +gpc_g8b(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else if (in->a >= 255) + { + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = in->g; + + else + out->r = out->g = out->b = sRGB(YfromRGB( + sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + } + + else + { + double a = in->a/255.; + + out->r = out->g = out->b = sRGB(a * YfromRGB(sRGB_to_d[in->r], + sRGB_to_d[in->g], sRGB_to_d[in->b]) + back->dg * (1-a)); + } + + out->a = 255; +} + +/* 8-bit to 16-bit conversions */ +/* lin: make sRGB components linear, alpha := 65535 */ +static void +gpc_lin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilinear(in->r); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilinear(in->b); + } + + else + { + out->g = ilinear(in->g); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilinear(in->b); + } + + out->a = 65535; +} + +/* pre: make sRGB components linear and premultiply by alpha (scale alpha) */ +static void +gpc_pre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara(in->b, in->a); + } + + else + { + out->g = ilineara(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara(in->b, in->a); + } + + out->a = in->a * 257; +} + +/* pre': as 'pre' but alpha := 65535 */ +static void +gpc_preq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara(in->b, in->a); + } + + else + { + out->g = ilineara(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara(in->b, in->a); + } + + out->a = 65535; +} + +/* glin: make sRGB components linear, convert to grayscale, alpha := 65535 */ +static void +gpc_glin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilinear(in->g); + + else + out->r = out->g = out->b = u16d(65535 * + YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = 65535; +} + +/* gpre: make sRGB components grayscale and linear and premultiply by alpha */ +static void +gpc_gpre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = 257 * in->a; +} + +/* gpr': as 'gpre' but alpha := 65535 */ +static void +gpc_gprq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); + + out->a = 65535; +} + +/* 8-bit to 16-bit conversions for gAMA 45455 encoded values */ +/* Lin: make gAMA 45455 components linear, alpha := 65535 */ +static void +gpc_Lin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilinear_g22(in->r); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilinear_g22(in->b); + } + + else + { + out->g = ilinear_g22(in->g); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilinear_g22(in->b); + } + + out->a = 65535; +} + +#if ALLOW_UNUSED_GPC +/* Pre: make gAMA 45455 components linear and premultiply by alpha (scale alpha) + */ +static void +gpc_Pre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara_g22(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara_g22(in->b, in->a); + } + + else + { + out->g = ilineara_g22(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara_g22(in->b, in->a); + } + + out->a = in->a * 257; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Pre': as 'Pre' but alpha := 65535 */ +static void +gpc_Preq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = ilineara_g22(in->r, in->a); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = ilineara_g22(in->b, in->a); + } + + else + { + out->g = ilineara_g22(in->g, in->a); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = ilineara_g22(in->b, in->a); + } + + out->a = 65535; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Glin: make gAMA 45455 components linear, convert to grayscale, alpha := 65535 + */ +static void +gpc_Glin(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilinear_g22(in->g); + + else + out->r = out->g = out->b = u16d(65535 * + YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + + out->a = 65535; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Gpre: make gAMA 45455 components grayscale and linear and premultiply by + * alpha. + */ +static void +gpc_Gpre(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara_g22(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + + out->a = 257 * in->a; +} +#endif + +#if ALLOW_UNUSED_GPC +/* Gpr': as 'Gpre' but alpha := 65535 */ +static void +gpc_Gprq(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->r == in->g && in->g == in->b) + out->r = out->g = out->b = ilineara_g22(in->g, in->a); + + else + out->r = out->g = out->b = u16d(in->a * 257 * + YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + + out->a = 65535; +} +#endif + +/* 16-bit to 8-bit conversions */ +/* sRGB: convert linear components to sRGB, alpha := 255 */ +static void +gpc_sRGB(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = isRGB(in->r); + + if (in->g == in->r) + { + out->g = out->r; + + if (in->b == in->r) + out->b = out->r; + + else + out->b = isRGB(in->b); + } + + else + { + out->g = isRGB(in->g); + + if (in->b == in->r) + out->b = out->r; + + else if (in->b == in->g) + out->b = out->g; + + else + out->b = isRGB(in->b); + } + + out->a = 255; +} + +/* unpg: unpremultiply gray component and convert to sRGB (scale alpha) */ +static void +gpc_unpg(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = out->g = out->b = sRGB((double)in->g / in->a); + out->a = u8d(in->a / 257.); + } +} + +/* unpc: unpremultiply color components and convert to sRGB (scale alpha) */ +static void +gpc_unpc(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = sRGB((double)in->r / in->a); + out->g = sRGB((double)in->g / in->a); + out->b = sRGB((double)in->b / in->a); + out->a = u8d(in->a / 257.); + } +} + +/* b16g: composite linear onto gray background and convert the result to sRGB */ +static void +gpc_b16g(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else + { + double a = in->a/65535.; + double a1 = 1-a; + + a /= 65535; + out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); + } + + out->a = 255; +} + +/* b16c: composite linear onto color background and convert the result to sRGB*/ +static void +gpc_b16c(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + { + out->r = back->ir; + out->g = back->ig; + out->b = back->ib; + } + + else + { + double a = in->a/65535.; + double a1 = 1-a; + + a /= 65535; + out->r = sRGB(in->r * a + back->dr * a1); + out->g = sRGB(in->g * a + back->dg * a1); + out->b = sRGB(in->b * a + back->db * a1); + } + + out->a = 255; +} + +/* sG: convert linear RGB to sRGB grayscale */ +static void +gpc_sG(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/65535); + out->a = 255; +} + +/* sGp: unpremultiply RGB then convert to sRGB grayscale */ +static void +gpc_sGp(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/in->a); + out->a = u8d(in->a / 257.); + } +} + +/* sCp: unpremultiply RGB then convert to sRGB */ +static void +gpc_sCp(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + + if (in->a <= 128) + { + out->r = out->g = out->b = 255; + out->a = 0; + } + + else + { + out->r = sRGB((double)in->r / in->a); + out->g = sRGB((double)in->g / in->a); + out->b = sRGB((double)in->b / in->a); + out->a = u8d(in->a / 257.); + } +} + +/* gb16: composite linear onto background and convert to sRGB grayscale */ +/* (order doesn't matter, the composite and grayscale operations permute) */ +static void +gpc_gb16(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + out->r = out->g = out->b = back->ig; + + else if (in->a >= 65535) + out->r = out->g = out->b = isRGB(in->g); + + else + { + double a = in->a / 65535.; + double a1 = 1-a; + + a /= 65535; + out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); + } + + out->a = 255; +} + +/* cb16: composite linear onto background and convert to sRGB */ +static void +gpc_cb16(Pixel *out, const Pixel *in, const Background *back) +{ + if (in->a <= 0) + { + out->r = back->ir; + out->g = back->ig; + out->b = back->ib; + } + + else if (in->a >= 65535) + { + out->r = isRGB(in->r); + out->g = isRGB(in->g); + out->b = isRGB(in->b); + } + + else + { + double a = in->a / 65535.; + double a1 = 1-a; + + a /= 65535; + out->r = sRGB(in->r * a + back->dr * a1); + out->g = sRGB(in->g * a + back->dg * a1); + out->b = sRGB(in->b * a + back->db * a1); + } + + out->a = 255; +} + +/* 16-bit to 16-bit conversions */ +/* A: set alpha to 65535 */ +static void +gpc_A(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = in->r; + out->g = in->g; + out->b = in->b; + out->a = 65535; +} + +/* g16: convert linear RGB to linear grayscale (alpha := 65535) */ +static void +gpc_g16(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); + out->a = 65535; +} + +/* g16': as 'g16' but alpha is unchanged */ +static void +gpc_g16q(Pixel *out, const Pixel *in, const Background *back) +{ + (void)back; + out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); + out->a = in->a; +} + +#if ALLOW_UNUSED_GPC +/* Unused functions (to hide them from GCC unused function warnings) */ +void (* const gpc_unused[]) + (Pixel *out, const Pixel *in, const Background *back) = +{ + gpc_Pre, gpc_Preq, gpc_Glin, gpc_Gpre, gpc_Gprq, gpc_nop8, gpc_nop6 +}; +#endif + +/* OUT: ----- 8-bit ----- ----- 16-bit ----- + * IN G GA RGB RGBA G GA RGB RGBA + * 8 G . . . . lin lin lin lin + * 8 GA bckg . bckc . pre' pre pre' pre + * 8 RGB g8 g8 . . glin glin lin lin + * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre + * 16 G sRGB sRGB sRGB sRGB . . . . + * 16 GA b16g unpg b16c unpc A . A . + * 16 RGB sG sG sRGB sRGB g16 g16 . . + * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . + * + * The matrix is held in an array indexed thus: + * + * gpc_fn[out_format & BASE_FORMATS][in_format & BASE_FORMATS]; + */ +/* This will produce a compile time error if the FORMAT_FLAG values don't + * match the above matrix! + */ +#if PNG_FORMAT_FLAG_ALPHA == 1 && PNG_FORMAT_FLAG_COLOR == 2 &&\ + PNG_FORMAT_FLAG_LINEAR == 4 +static void (* const gpc_fn[8/*in*/][8/*out*/]) + (Pixel *out, const Pixel *in, const Background *back) = +{ +/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ + {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_Lin, gpc_Lin, gpc_Lin, gpc_Lin }, + {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, + {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, + {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, + {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, + {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, + {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, + {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} +}; + +/* The array is repeated for the cases where both the input and output are color + * mapped because then different algorithms are used. + */ +static void (* const gpc_fn_colormapped[8/*in*/][8/*out*/]) + (Pixel *out, const Pixel *in, const Background *back) = +{ +/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ + {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_lin, gpc_lin, gpc_lin, gpc_lin }, + {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, + {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, + {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, + {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, + {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, + {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, + {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} +}; + +/* The error arrays record the error in the same matrix; 64 entries, however + * the different algorithms used in libpng for colormap and direct conversions + * mean that four separate matrices are used (for each combination of + * colormapped and direct.) + * + * In some cases the conversion between sRGB formats goes via a linear + * intermediate; an sRGB to linear conversion (as above) is followed by a simple + * linear to sRGB step with no other conversions. This is done by a separate + * error array from an arbitrary 'in' format to one of the four basic outputs + * (since final output is always sRGB not colormapped). + * + * These arrays may be modified if the --accumulate flag is set during the run; + * then instead of logging errors they are simply added in. + * + * The three entries are currently for transparent, partially transparent and + * opaque input pixel values. Notice that alpha should be exact in each case. + * + * Errors in alpha should only occur when converting from a direct format + * to a colormapped format, when alpha is effectively smashed (so large + * errors can occur.) There should be no error in the '0' and 'opaque' + * values. The fourth entry in the array is used for the alpha error (and it + * should always be zero for the 'via linear' case since this is never color + * mapped.) + * + * Mapping to a colormap smashes the colors, it is necessary to have separate + * values for these cases because they are much larger; it is very much + * impossible to obtain a reasonable result, these are held in + * gpc_error_to_colormap. + */ +#if PNG_FORMAT_FLAG_COLORMAP == 8 /* extra check also required */ +/* START MACHINE GENERATED */ +static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] = +{ + { /* input: sRGB-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: sRGB-gray+alpha */ + { 0, 18, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: sRGB-rgb */ + { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: sRGB-rgb+alpha */ + { 0, 4, 13, 0 }, { 0, 14, 13, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 832, 764, 0 }, { 0, 832, 764, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-gray */ + { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-gray+alpha */ + { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, + { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-rgb */ + { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, + { 0, 0, 4, 0 }, { 0, 0, 4, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: linear-rgb+alpha */ + { 0, 126, 143, 0 }, { 0, 9, 7, 0 }, { 0, 74, 9, 0 }, { 0, 16, 9, 0 }, + { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-rgb */ + { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 8, 0 }, { 0, 0, 8, 0 }, + { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 }, + { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 } + }, { /* input: color-mapped-sRGB-rgb+alpha */ + { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 8, 0 }, { 0, 9, 8, 0 }, + { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 409, 0 }, { 0, 717, 409, 0 }, + { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 13323, 460, 0 }, { 0, 334, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 } + }, { /* input: color-mapped-linear-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 } + } +}; +static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] = +{ + { /* input: sRGB-gray */ + { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 } + }, { /* input: sRGB-gray+alpha */ + { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 } + }, { /* input: sRGB-rgb */ + { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 } + }, { /* input: sRGB-rgb+alpha */ + { 0, 12, 14, 0 }, { 0, 180, 14, 0 }, { 0, 14, 15, 0 }, { 0, 186, 15, 0 } + }, { /* input: linear-gray */ + { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } + }, { /* input: linear-gray+alpha */ + { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } + }, { /* input: linear-rgb */ + { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } + }, { /* input: linear-rgb+alpha */ + { 0, 1, 1, 0 }, { 0, 8, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } + }, { /* input: color-mapped-sRGB-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-sRGB-rgb */ + { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 } + }, { /* input: color-mapped-sRGB-rgb+alpha */ + { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 8, 3, 0 }, { 0, 32, 3, 0 } + }, { /* input: color-mapped-linear-gray */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-gray+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + }, { /* input: color-mapped-linear-rgb+alpha */ + { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } + } +}; +static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] = +{ + { /* input: sRGB-gray */ + { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, + { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 } + }, { /* input: sRGB-gray+alpha */ + { 0, 19, 2, 0 }, { 0, 255, 2, 25 }, { 0, 88, 2, 0 }, { 0, 255, 2, 25 }, + { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }, { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 } + }, { /* input: sRGB-rgb */ + { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 }, + { 0, 0, 937, 0 }, { 0, 0, 937, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 } + }, { /* input: sRGB-rgb+alpha */ + { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 220, 25, 0 }, { 0, 255, 25, 67 }, + { 0, 17534, 18491, 0 }, { 0, 15614, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 48573, 13677, 17219 } + }, { /* input: linear-gray */ + { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, + { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 } + }, { /* input: linear-gray+alpha */ + { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 97, 74, 0 }, { 0, 255, 74, 25 }, + { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 } + }, { /* input: linear-rgb */ + { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 }, + { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 } + }, { /* input: linear-rgb+alpha */ + { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 }, + { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 46509, 24992, 17347 } + } +}; +/* END MACHINE GENERATED */ +#endif /* COLORMAP flag check */ +#endif /* flag checks */ + +typedef struct +{ + /* Basic pixel information: */ + Image* in_image; /* Input image */ + const Image* out_image; /* Output image */ + + /* 'background' is the value passed to the gpc_ routines, it may be NULL if + * it should not be used (*this* program has an error if it crashes as a + * result!) + */ + Background background_color; + const Background* background; + + /* Precalculated values: */ + int in_opaque; /* Value of input alpha that is opaque */ + int is_palette; /* Sample values come from the palette */ + int accumulate; /* Accumlate component errors (don't log) */ + int output_8bit; /* Output is 8 bit (else 16 bit) */ + + void (*in_gp)(Pixel*, png_const_voidp); + void (*out_gp)(Pixel*, png_const_voidp); + + void (*transform)(Pixel *out, const Pixel *in, const Background *back); + /* A function to perform the required transform */ + + void (*from_linear)(Pixel *out, const Pixel *in, const Background *back); + /* For 'via_linear' transforms the final, from linear, step, else NULL */ + + png_uint_16 error[4]; + /* Three error values for transparent, partially transparent and opaque + * input pixels (in turn). + */ + + png_uint_16 *error_ptr; + /* Where these are stored in the static array (for 'accumulate') */ +} +Transform; + +/* Return a 'transform' as above for the given format conversion. */ +static void +transform_from_formats(Transform *result, Image *in_image, + const Image *out_image, png_const_colorp background, int via_linear) +{ + png_uint_32 in_format, out_format; + png_uint_32 in_base, out_base; + + memset(result, 0, sizeof *result); + + /* Store the original images for error messages */ + result->in_image = in_image; + result->out_image = out_image; + + in_format = in_image->image.format; + out_format = out_image->image.format; + + if (in_format & PNG_FORMAT_FLAG_LINEAR) + result->in_opaque = 65535; + else + result->in_opaque = 255; + + result->output_8bit = (out_format & PNG_FORMAT_FLAG_LINEAR) == 0; + + result->is_palette = 0; /* set by caller if required */ + result->accumulate = (in_image->opts & ACCUMULATE) != 0; + + /* The loaders (which need the ordering information) */ + result->in_gp = get_pixel(in_format); + result->out_gp = get_pixel(out_format); + + /* Remove the ordering information: */ + in_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; + in_base = in_format & BASE_FORMATS; + out_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; + out_base = out_format & BASE_FORMATS; + + if (via_linear) + { + /* Check for an error in this program: */ + if (out_format & (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLORMAP)) + { + fprintf(stderr, "internal transform via linear error 0x%x->0x%x\n", + in_format, out_format); + exit(1); + } + + result->transform = gpc_fn[in_base][out_base | PNG_FORMAT_FLAG_LINEAR]; + result->from_linear = gpc_fn[out_base | PNG_FORMAT_FLAG_LINEAR][out_base]; + result->error_ptr = gpc_error_via_linear[in_format][out_format]; + } + + else if (~in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) + { + /* The input is not colormapped but the output is, the errors will + * typically be large (only the grayscale-no-alpha case permits preserving + * even 8-bit values.) + */ + result->transform = gpc_fn[in_base][out_base]; + result->from_linear = NULL; + result->error_ptr = gpc_error_to_colormap[in_base][out_base]; + } + + else + { + /* The caller handles the colormap->pixel value conversion, so the + * transform function just gets a pixel value, however because libpng + * currently contains a different implementation for mapping a colormap if + * both input and output are colormapped we need different conversion + * functions to deal with errors in the libpng implementation. + */ + if (in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) + result->transform = gpc_fn_colormapped[in_base][out_base]; + else + result->transform = gpc_fn[in_base][out_base]; + result->from_linear = NULL; + result->error_ptr = gpc_error[in_format][out_format]; + } + + /* Follow the libpng simplified API rules to work out what to pass to the gpc + * routines as a background value, if one is not required pass NULL so that + * this program crashes in the even of a programming error. + */ + result->background = NULL; /* default: not required */ + + /* Rule 1: background only need be supplied if alpha is to be removed */ + if (in_format & ~out_format & PNG_FORMAT_FLAG_ALPHA) + { + /* The input value is 'NULL' to use the background and (otherwise) an sRGB + * background color (to use a solid color). The code above uses a fixed + * byte value, BUFFER_INIT8, for buffer even for 16-bit output. For + * linear (16-bit) output the sRGB background color is ignored; the + * composition is always on the background (so BUFFER_INIT8 * 257), except + * that for the colormap (i.e. linear colormapped output) black is used. + */ + result->background = &result->background_color; + + if (out_format & PNG_FORMAT_FLAG_LINEAR || via_linear) + { + if (out_format & PNG_FORMAT_FLAG_COLORMAP) + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = 0; + result->background_color.dr = + result->background_color.dg = + result->background_color.db = 0; + } + + else + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = BUFFER_INIT8 * 257; + result->background_color.dr = + result->background_color.dg = + result->background_color.db = 0; + } + } + + else /* sRGB output */ + { + if (background != NULL) + { + if (out_format & PNG_FORMAT_FLAG_COLOR) + { + result->background_color.ir = background->red; + result->background_color.ig = background->green; + result->background_color.ib = background->blue; + /* TODO: sometimes libpng uses the power law conversion here, how + * to handle this? + */ + result->background_color.dr = sRGB_to_d[background->red]; + result->background_color.dg = sRGB_to_d[background->green]; + result->background_color.db = sRGB_to_d[background->blue]; + } + + else /* grayscale: libpng only looks at 'g' */ + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = background->green; + /* TODO: sometimes libpng uses the power law conversion here, how + * to handle this? + */ + result->background_color.dr = + result->background_color.dg = + result->background_color.db = sRGB_to_d[background->green]; + } + } + + else if ((out_format & PNG_FORMAT_FLAG_COLORMAP) == 0) + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = BUFFER_INIT8; + /* TODO: sometimes libpng uses the power law conversion here, how + * to handle this? + */ + result->background_color.dr = + result->background_color.dg = + result->background_color.db = sRGB_to_d[BUFFER_INIT8]; + } + + /* Else the output is colormapped and a background color must be + * provided; if pngstest crashes then that is a bug in this program + * (though libpng should png_error as well.) + */ + else + result->background = NULL; + } + } + + if (result->background == NULL) + { + result->background_color.ir = + result->background_color.ig = + result->background_color.ib = -1; /* not used */ + result->background_color.dr = + result->background_color.dg = + result->background_color.db = 1E30; /* not used */ + } + + + /* Copy the error values into the Transform: */ + result->error[0] = result->error_ptr[0]; + result->error[1] = result->error_ptr[1]; + result->error[2] = result->error_ptr[2]; + result->error[3] = result->error_ptr[3]; +} + + +/* Compare two pixels. + * + * OLD error values: +static int error_to_linear = 811; * by experiment * +static int error_to_linear_grayscale = 424; * by experiment * +static int error_to_sRGB = 6; * by experiment * +static int error_to_sRGB_grayscale = 17; * libpng error by calculation + + 2 by experiment * +static int error_in_compose = 2; * by experiment * +static int error_in_premultiply = 1; + * + * The following is *just* the result of a round trip from 8-bit sRGB to linear + * then back to 8-bit sRGB when it is done by libpng. There are two problems: + * + * 1) libpng currently uses a 2.2 power law with no linear segment, this results + * in instability in the low values and even with 16-bit precision sRGB(1) ends + * up mapping to sRGB(0) as a result of rounding in the 16-bit representation. + * This gives an error of 1 in the handling of value 1 only. + * + * 2) libpng currently uses an intermediate 8-bit linear value in gamma + * correction of 8-bit values. This results in many more errors, the worse of + * which is mapping sRGB(14) to sRGB(0). + * + * The general 'error_via_linear' is more complex because of pre-multiplication, + * this compounds the 8-bit errors according to the alpha value of the pixel. + * As a result 256 values are pre-calculated for error_via_linear. + */ +#if 0 +static int error_in_libpng_gamma; +static int error_via_linear[256]; /* Indexed by 8-bit alpha */ + +static void +init_error_via_linear(void) +{ + int alpha; + + error_via_linear[0] = 255; /* transparent pixel */ + + for (alpha=1; alpha<=255; ++alpha) + { + /* 16-bit values less than 128.5 get rounded to 8-bit 0 and so the worst + * case error arises with 16-bit 128.5, work out what sRGB + * (non-associated) value generates 128.5; any value less than this is + * going to map to 0, so the worst error is floor(value). + * + * Note that errors are considerably higher (more than a factor of 2) + * because libpng uses a simple power law for sRGB data at present. + * + * Add .1 for arithmetic errors inside libpng. + */ + double v = floor(255*pow(.5/*(128.5 * 255 / 65535)*/ / alpha, 1/2.2)+.1); + + error_via_linear[alpha] = (int)v; + } + + /* This is actually 14.99, but, despite the closeness to 15, 14 seems to work + * ok in this case. + */ + error_in_libpng_gamma = 14; +} +#endif + +static void +print_pixel(char string[64], const Pixel *pixel, png_uint_32 format) +{ + switch (format & (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR)) + { + case 0: + sprintf(string, "%s(%d)", format_names[format], pixel->g); + break; + + case PNG_FORMAT_FLAG_ALPHA: + sprintf(string, "%s(%d,%d)", format_names[format], pixel->g, + pixel->a); + break; + + case PNG_FORMAT_FLAG_COLOR: + sprintf(string, "%s(%d,%d,%d)", format_names[format], + pixel->r, pixel->g, pixel->b); + break; + + case PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA: + sprintf(string, "%s(%d,%d,%d,%d)", format_names[format], + pixel->r, pixel->g, pixel->b, pixel->a); + break; + + default: + sprintf(string, "invalid-format"); + break; + } +} + +static int +logpixel(const Transform *transform, png_uint_32 x, png_uint_32 y, + const Pixel *in, const Pixel *calc, const Pixel *out, const char *reason) +{ + const png_uint_32 in_format = transform->in_image->image.format; + const png_uint_32 out_format = transform->out_image->image.format; + + png_uint_32 back_format = out_format & ~PNG_FORMAT_FLAG_ALPHA; + const char *via_linear = ""; + + char pixel_in[64], pixel_calc[64], pixel_out[64], pixel_loc[64]; + char background_info[100]; + + print_pixel(pixel_in, in, in_format); + print_pixel(pixel_calc, calc, out_format); + print_pixel(pixel_out, out, out_format); + + if (transform->is_palette) + sprintf(pixel_loc, "palette: %lu", (unsigned long)y); + else + sprintf(pixel_loc, "%lu,%lu", (unsigned long)x, (unsigned long)y); + + if (transform->from_linear != NULL) + { + via_linear = " (via linear)"; + /* And as a result the *read* format which did any background processing + * was itself linear, so the background color information is also + * linear. + */ + back_format |= PNG_FORMAT_FLAG_LINEAR; + } + + if (transform->background != NULL) + { + Pixel back; + char pixel_back[64]; + + back.r = transform->background->ir; + back.g = transform->background->ig; + back.b = transform->background->ib; + back.a = -1; /* not used */ + + print_pixel(pixel_back, &back, back_format); + sprintf(background_info, " on background %s", pixel_back); + } + + else + background_info[0] = 0; + + if (transform->in_image->file_name != transform->out_image->file_name) + { + char error_buffer[512]; + sprintf(error_buffer, + "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" + "Use --preserve and examine: ", pixel_loc, reason, via_linear, + pixel_in, background_info, pixel_out, pixel_calc); + return logerror(transform->in_image, transform->in_image->file_name, + error_buffer, transform->out_image->file_name); + } + + else + { + char error_buffer[512]; + sprintf(error_buffer, + "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" + " The error happened when reading the original file with this format.", + pixel_loc, reason, via_linear, pixel_in, background_info, pixel_out, + pixel_calc); + return logerror(transform->in_image, transform->in_image->file_name, + error_buffer, ""); + } +} + +static int +cmppixel(Transform *transform, png_const_voidp in, png_const_voidp out, + png_uint_32 x, png_uint_32 y/*or palette index*/) +{ + int maxerr; + png_const_charp errmsg; + Pixel pixel_in, pixel_calc, pixel_out; + + transform->in_gp(&pixel_in, in); + + if (transform->from_linear == NULL) + transform->transform(&pixel_calc, &pixel_in, transform->background); + + else + { + transform->transform(&pixel_out, &pixel_in, transform->background); + transform->from_linear(&pixel_calc, &pixel_out, NULL); + } + + transform->out_gp(&pixel_out, out); + + /* Eliminate the case where the input and output values match exactly. */ + if (pixel_calc.a == pixel_out.a && pixel_calc.r == pixel_out.r && + pixel_calc.g == pixel_out.g && pixel_calc.b == pixel_out.b) + return 1; + + /* Eliminate the case where the output pixel is transparent and the output + * is 8-bit - any component values are valid. Don't check the input alpha + * here to also skip the 16-bit small alpha cases. + */ + if (transform->output_8bit && pixel_calc.a == 0 && pixel_out.a == 0) + return 1; + + /* Check for alpha errors first; an alpha error can damage the components too + * so avoid spurious checks on components if one is found. + */ + errmsg = NULL; + { + int err_a = abs(pixel_calc.a-pixel_out.a); + + if (err_a > transform->error[3]) + { + /* If accumulating check the components too */ + if (transform->accumulate) + transform->error[3] = (png_uint_16)err_a; + + else + errmsg = "alpha"; + } + } + + /* Now if *either* of the output alphas are 0 but alpha is within tolerance + * eliminate the 8-bit component comparison. + */ + if (errmsg == NULL && transform->output_8bit && + (pixel_calc.a == 0 || pixel_out.a == 0)) + return 1; + + if (errmsg == NULL) /* else just signal an alpha error */ + { + int err_r = abs(pixel_calc.r - pixel_out.r); + int err_g = abs(pixel_calc.g - pixel_out.g); + int err_b = abs(pixel_calc.b - pixel_out.b); + int limit; + + if ((err_r | err_g | err_b) == 0) + return 1; /* exact match */ + + /* Mismatch on a component, check the input alpha */ + if (pixel_in.a >= transform->in_opaque) + { + errmsg = "opaque component"; + limit = 2; /* opaque */ + } + + else if (pixel_in.a > 0) + { + errmsg = "alpha component"; + limit = 1; /* partially transparent */ + } + + else + { + errmsg = "transparent component (background)"; + limit = 0; /* transparent */ + } + + maxerr = err_r; + if (maxerr < err_g) maxerr = err_g; + if (maxerr < err_b) maxerr = err_b; + + if (maxerr <= transform->error[limit]) + return 1; /* within the error limits */ + + /* Handle a component mis-match; log it, just return an error code, or + * accumulate it. + */ + if (transform->accumulate) + { + transform->error[limit] = (png_uint_16)maxerr; + return 1; /* to cause the caller to keep going */ + } + } + + /* Failure to match and not accumulating, so the error must be logged. */ + return logpixel(transform, x, y, &pixel_in, &pixel_calc, &pixel_out, errmsg); +} + +static png_byte +component_loc(png_byte loc[4], png_uint_32 format) +{ + /* Given a format return the number of channels and the location of + * each channel. + * + * The mask 'loc' contains the component offset of the channels in the + * following order. Note that if 'format' is grayscale the entries 1-3 must + * all contain the location of the gray channel. + * + * 0: alpha + * 1: red or gray + * 2: green or gray + * 3: blue or gray + */ + png_byte channels; + + if (format & PNG_FORMAT_FLAG_COLOR) + { + channels = 3; + + loc[2] = 1; + + if (format & PNG_FORMAT_FLAG_BGR) + { + loc[1] = 2; + loc[3] = 0; + } + + else + { + loc[1] = 0; + loc[3] = 2; + } + } + + else + { + channels = 1; + loc[1] = loc[2] = loc[3] = 0; + } + + if (format & PNG_FORMAT_FLAG_ALPHA) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + { + loc[0] = 0; + ++loc[1]; + ++loc[2]; + ++loc[3]; + } + + else + loc[0] = channels; + + ++channels; + } + + else + loc[0] = 4; /* not present */ + + return channels; +} + +/* Compare two images, the original 'a', which was written out then read back in + * to * give image 'b'. The formats may have been changed. + */ +static int +compare_two_images(Image *a, Image *b, int via_linear, + png_const_colorp background) +{ + ptrdiff_t stridea = a->stride; + ptrdiff_t strideb = b->stride; + png_const_bytep rowa = a->buffer+16; + png_const_bytep rowb = b->buffer+16; + const png_uint_32 width = a->image.width; + const png_uint_32 height = a->image.height; + const png_uint_32 formata = a->image.format; + const png_uint_32 formatb = b->image.format; + const unsigned int a_sample = PNG_IMAGE_SAMPLE_SIZE(formata); + const unsigned int b_sample = PNG_IMAGE_SAMPLE_SIZE(formatb); + int alpha_added, alpha_removed; + int bchannels; + int btoa[4]; + png_uint_32 y; + Transform tr; + + /* This should never happen: */ + if (width != b->image.width || height != b->image.height) + return logerror(a, a->file_name, ": width x height changed: ", + b->file_name); + + /* Set up the background and the transform */ + transform_from_formats(&tr, a, b, background, via_linear); + + /* Find the first row and inter-row space. */ + if (!(formata & PNG_FORMAT_FLAG_COLORMAP) && + (formata & PNG_FORMAT_FLAG_LINEAR)) + stridea *= 2; + + if (!(formatb & PNG_FORMAT_FLAG_COLORMAP) && + (formatb & PNG_FORMAT_FLAG_LINEAR)) + strideb *= 2; + + if (stridea < 0) rowa += (height-1) * (-stridea); + if (strideb < 0) rowb += (height-1) * (-strideb); + + /* First shortcut the two colormap case by comparing the image data; if it + * matches then we expect the colormaps to match, although this is not + * absolutely necessary for an image match. If the colormaps fail to match + * then there is a problem in libpng. + */ + if (formata & formatb & PNG_FORMAT_FLAG_COLORMAP) + { + /* Only check colormap entries that actually exist; */ + png_const_bytep ppa, ppb; + int match; + png_byte in_use[256], amax = 0, bmax = 0; + + memset(in_use, 0, sizeof in_use); + + ppa = rowa; + ppb = rowb; + + /* Do this the slow way to accumulate the 'in_use' flags, don't break out + * of the loop until the end; this validates the color-mapped data to + * ensure all pixels are valid color-map indexes. + */ + for (y=0, match=1; y bmax) + bmax = bval; + + if (bval != aval) + match = 0; + + in_use[aval] = 1; + if (aval > amax) + amax = aval; + } + } + + /* If the buffers match then the colormaps must too. */ + if (match) + { + /* Do the color-maps match, entry by entry? Only check the 'in_use' + * entries. An error here should be logged as a color-map error. + */ + png_const_bytep a_cmap = (png_const_bytep)a->colormap; + png_const_bytep b_cmap = (png_const_bytep)b->colormap; + int result = 1; /* match by default */ + + /* This is used in logpixel to get the error message correct. */ + tr.is_palette = 1; + + for (y=0; y<256; ++y, a_cmap += a_sample, b_cmap += b_sample) + if (in_use[y]) + { + /* The colormap entries should be valid, but because libpng doesn't + * do any checking at present the original image may contain invalid + * pixel values. These cause an error here (at present) unless + * accumulating errors in which case the program just ignores them. + */ + if (y >= a->image.colormap_entries) + { + if ((a->opts & ACCUMULATE) == 0) + { + char pindex[9]; + sprintf(pindex, "%lu[%lu]", (unsigned long)y, + (unsigned long)a->image.colormap_entries); + logerror(a, a->file_name, ": bad pixel index: ", pindex); + } + result = 0; + } + + else if (y >= b->image.colormap_entries) + { + if ((a->opts & ACCUMULATE) == 0) + { + char pindex[9]; + sprintf(pindex, "%lu[%lu]", (unsigned long)y, + (unsigned long)b->image.colormap_entries); + logerror(b, b->file_name, ": bad pixel index: ", pindex); + } + result = 0; + } + + /* All the mismatches are logged here; there can only be 256! */ + else if (!cmppixel(&tr, a_cmap, b_cmap, 0, y)) + result = 0; + } + + /* If reqested copy the error values back from the Transform. */ + if (a->opts & ACCUMULATE) + { + tr.error_ptr[0] = tr.error[0]; + tr.error_ptr[1] = tr.error[1]; + tr.error_ptr[2] = tr.error[2]; + tr.error_ptr[3] = tr.error[3]; + result = 1; /* force a continue */ + } + + return result; + } + + /* else the image buffers don't match pixel-wise so compare sample values + * instead, but first validate that the pixel indexes are in range (but + * only if not accumulating, when the error is ignored.) + */ + else if ((a->opts & ACCUMULATE) == 0) + { + /* Check the original image first, + * TODO: deal with input images with bad pixel values? + */ + if (amax >= a->image.colormap_entries) + { + char pindex[9]; + sprintf(pindex, "%d[%lu]", amax, + (unsigned long)a->image.colormap_entries); + return logerror(a, a->file_name, ": bad pixel index: ", pindex); + } + + else if (bmax >= b->image.colormap_entries) + { + char pindex[9]; + sprintf(pindex, "%d[%lu]", bmax, + (unsigned long)b->image.colormap_entries); + return logerror(b, b->file_name, ": bad pixel index: ", pindex); + } + } + } + + /* We can directly compare pixel values without the need to use the read + * or transform support (i.e. a memory compare) if: + * + * 1) The bit depth has not changed. + * 2) RGB to grayscale has not been done (the reverse is ok; we just compare + * the three RGB values to the original grayscale.) + * 3) An alpha channel has not been removed from an 8-bit format, or the + * 8-bit alpha value of the pixel was 255 (opaque). + * + * If an alpha channel has been *added* then it must have the relevant opaque + * value (255 or 65535). + * + * The fist two the tests (in the order given above) (using the boolean + * equivalence !a && !b == !(a || b)) + */ + if (!(((formata ^ formatb) & PNG_FORMAT_FLAG_LINEAR) | + (formata & (formatb ^ PNG_FORMAT_FLAG_COLOR) & PNG_FORMAT_FLAG_COLOR))) + { + /* Was an alpha channel changed? */ + const png_uint_32 alpha_changed = (formata ^ formatb) & + PNG_FORMAT_FLAG_ALPHA; + + /* Was an alpha channel removed? (The third test.) If so the direct + * comparison is only possible if the input alpha is opaque. + */ + alpha_removed = (formata & alpha_changed) != 0; + + /* Was an alpha channel added? */ + alpha_added = (formatb & alpha_changed) != 0; + + /* The channels may have been moved between input and output, this finds + * out how, recording the result in the btoa array, which says where in + * 'a' to find each channel of 'b'. If alpha was added then btoa[alpha] + * ends up as 4 (and is not used.) + */ + { + int i; + png_byte aloc[4]; + png_byte bloc[4]; + + /* The following are used only if the formats match, except that + * 'bchannels' is a flag for matching formats. btoa[x] says, for each + * channel in b, where to find the corresponding value in a, for the + * bchannels. achannels may be different for a gray to rgb transform + * (a will be 1 or 2, b will be 3 or 4 channels.) + */ + (void)component_loc(aloc, formata); + bchannels = component_loc(bloc, formatb); + + /* Hence the btoa array. */ + for (i=0; i<4; ++i) if (bloc[i] < 4) + btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */ + + if (alpha_added) + alpha_added = bloc[0]; /* location of alpha channel in image b */ + + else + alpha_added = 4; /* Won't match an image b channel */ + + if (alpha_removed) + alpha_removed = aloc[0]; /* location of alpha channel in image a */ + + else + alpha_removed = 4; + } + } + + else + { + /* Direct compare is not possible, cancel out all the corresponding local + * variables. + */ + bchannels = 0; + alpha_removed = alpha_added = 4; + btoa[3] = btoa[2] = btoa[1] = btoa[0] = 4; /* 4 == not present */ + } + + for (y=0; ycolormap + a_sample * *ppa++; + else + psa = ppa, ppa += a_sample; + + if (formatb & PNG_FORMAT_FLAG_COLORMAP) + psb = (png_const_bytep)b->colormap + b_sample * *ppb++; + else + psb = ppb, ppb += b_sample; + + /* Do the fast test if possible. */ + if (bchannels) + { + /* Check each 'b' channel against either the corresponding 'a' + * channel or the opaque alpha value, as appropriate. If + * alpha_removed value is set (not 4) then also do this only if the + * 'a' alpha channel (alpha_removed) is opaque; only relevant for + * the 8-bit case. + */ + if (formatb & PNG_FORMAT_FLAG_LINEAR) /* 16-bit checks */ + { + png_const_uint_16p pua = aligncastconst(png_const_uint_16p, psa); + png_const_uint_16p pub = aligncastconst(png_const_uint_16p, psb); + + switch (bchannels) + { + case 4: + if (pua[btoa[3]] != pub[3]) break; + case 3: + if (pua[btoa[2]] != pub[2]) break; + case 2: + if (pua[btoa[1]] != pub[1]) break; + case 1: + if (pua[btoa[0]] != pub[0]) break; + if (alpha_added != 4 && pub[alpha_added] != 65535) break; + continue; /* x loop */ + default: + break; /* impossible */ + } + } + + else if (alpha_removed == 4 || psa[alpha_removed] == 255) + { + switch (bchannels) + { + case 4: + if (psa[btoa[3]] != psb[3]) break; + case 3: + if (psa[btoa[2]] != psb[2]) break; + case 2: + if (psa[btoa[1]] != psb[1]) break; + case 1: + if (psa[btoa[0]] != psb[0]) break; + if (alpha_added != 4 && psb[alpha_added] != 255) break; + continue; /* x loop */ + default: + break; /* impossible */ + } + } + } + + /* If we get to here the fast match failed; do the slow match for this + * pixel. + */ + if (!cmppixel(&tr, psa, psb, x, y) && (a->opts & KEEP_GOING) == 0) + return 0; /* error case */ + } + } + + /* If reqested copy the error values back from the Transform. */ + if (a->opts & ACCUMULATE) + { + tr.error_ptr[0] = tr.error[0]; + tr.error_ptr[1] = tr.error[1]; + tr.error_ptr[2] = tr.error[2]; + tr.error_ptr[3] = tr.error[3]; + } + + return 1; +} + +/* Read the file; how the read gets done depends on which of input_file and + * input_memory have been set. + */ +static int +read_file(Image *image, png_uint_32 format, png_const_colorp background) +{ + memset(&image->image, 0, sizeof image->image); + image->image.version = PNG_IMAGE_VERSION; + + if (image->input_memory != NULL) + { + if (!png_image_begin_read_from_memory(&image->image, image->input_memory, + image->input_memory_size)) + return logerror(image, "memory init: ", image->file_name, ""); + } + + else if (image->input_file != NULL) + { + if (!png_image_begin_read_from_stdio(&image->image, image->input_file)) + return logerror(image, "stdio init: ", image->file_name, ""); + } + + else + { + if (!png_image_begin_read_from_file(&image->image, image->file_name)) + return logerror(image, "file init: ", image->file_name, ""); + } + + /* This must be set after the begin_read call: */ + if (image->opts & sRGB_16BIT) + image->image.flags |= PNG_IMAGE_FLAG_16BIT_sRGB; + + /* Have an initialized image with all the data we need plus, maybe, an + * allocated file (myfile) or buffer (mybuffer) that need to be freed. + */ + { + int result; + png_uint_32 image_format; + + /* Print both original and output formats. */ + image_format = image->image.format; + + if (image->opts & VERBOSE) + { + printf("%s %lu x %lu %s -> %s", image->file_name, + (unsigned long)image->image.width, + (unsigned long)image->image.height, + format_names[image_format & FORMAT_MASK], + (format & FORMAT_NO_CHANGE) != 0 || image->image.format == format + ? "no change" : format_names[format & FORMAT_MASK]); + + if (background != NULL) + printf(" background(%d,%d,%d)\n", background->red, + background->green, background->blue); + else + printf("\n"); + + fflush(stdout); + } + + /* 'NO_CHANGE' combined with the color-map flag forces the base format + * flags to be set on read to ensure that the original representation is + * not lost in the pass through a colormap format. + */ + if ((format & FORMAT_NO_CHANGE) != 0) + { + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && + (image_format & PNG_FORMAT_FLAG_COLORMAP) != 0) + format = (image_format & ~BASE_FORMATS) | (format & BASE_FORMATS); + + else + format = image_format; + } + + image->image.format = format; + + image->stride = PNG_IMAGE_ROW_STRIDE(image->image) + image->stride_extra; + allocbuffer(image); + + result = png_image_finish_read(&image->image, background, + image->buffer+16, (png_int_32)image->stride, image->colormap); + + checkbuffer(image, image->file_name); + + if (result) + return checkopaque(image); + + else + return logerror(image, image->file_name, ": image read failed", ""); + } +} + +/* Reads from a filename, which must be in image->file_name, but uses + * image->opts to choose the method. The file is always read in its native + * format (the one the simplified API suggests). + */ +static int +read_one_file(Image *image) +{ + if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO)) + { + /* memory or stdio. */ + FILE *f = fopen(image->file_name, "rb"); + + if (f != NULL) + { + if (image->opts & READ_FILE) + image->input_file = f; + + else /* memory */ + { + if (fseek(f, 0, SEEK_END) == 0) + { + long int cb = ftell(f); + + if (cb > 0 && (unsigned long int)cb < (size_t)~(size_t)0) + { + png_bytep b = voidcast(png_bytep, malloc((size_t)cb)); + + if (b != NULL) + { + rewind(f); + + if (fread(b, (size_t)cb, 1, f) == 1) + { + fclose(f); + image->input_memory_size = cb; + image->input_memory = b; + } + + else + { + free(b); + return logclose(image, f, image->file_name, + ": read failed: "); + } + } + + else + return logclose(image, f, image->file_name, + ": out of memory: "); + } + + else if (cb == 0) + return logclose(image, f, image->file_name, + ": zero length: "); + + else + return logclose(image, f, image->file_name, + ": tell failed: "); + } + + else + return logclose(image, f, image->file_name, ": seek failed: "); + } + } + + else + return logerror(image, image->file_name, ": open failed: ", + strerror(errno)); + } + + return read_file(image, FORMAT_NO_CHANGE, NULL); +} + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +static int +write_one_file(Image *output, Image *image, int convert_to_8bit) +{ + if (image->opts & FAST_WRITE) + image->image.flags |= PNG_IMAGE_FLAG_FAST; + + if (image->opts & USE_STDIO) + { + FILE *f = tmpfile(); + + if (f != NULL) + { + if (png_image_write_to_stdio(&image->image, f, convert_to_8bit, + image->buffer+16, (png_int_32)image->stride, image->colormap)) + { + if (fflush(f) == 0) + { + rewind(f); + initimage(output, image->opts, "tmpfile", image->stride_extra); + output->input_file = f; + if (!checkopaque(image)) + return 0; + } + + else + return logclose(image, f, "tmpfile", ": flush: "); + } + + else + { + fclose(f); + return logerror(image, "tmpfile", ": write failed", ""); + } + } + + else + return logerror(image, "tmpfile", ": open: ", strerror(errno)); + } + + else + { + static int counter = 0; + char name[32]; + + sprintf(name, "%s%d.png", tmpf, ++counter); + + if (png_image_write_to_file(&image->image, name, convert_to_8bit, + image->buffer+16, (png_int_32)image->stride, image->colormap)) + { + initimage(output, image->opts, output->tmpfile_name, + image->stride_extra); + /* Afterwards, or freeimage will delete it! */ + strcpy(output->tmpfile_name, name); + + if (!checkopaque(image)) + return 0; + } + + else + return logerror(image, name, ": write failed", ""); + } + + /* 'output' has an initialized temporary image, read this back in and compare + * this against the original: there should be no change since the original + * format was written unmodified unless 'convert_to_8bit' was specified. + * However, if the original image was color-mapped, a simple read will zap + * the linear, color and maybe alpha flags, this will cause spurious failures + * under some circumstances. + */ + if (read_file(output, image->image.format | FORMAT_NO_CHANGE, NULL)) + { + png_uint_32 original_format = image->image.format; + + if (convert_to_8bit) + original_format &= ~PNG_FORMAT_FLAG_LINEAR; + + if ((output->image.format & BASE_FORMATS) != + (original_format & BASE_FORMATS)) + return logerror(image, image->file_name, ": format changed on read: ", + output->file_name); + + return compare_two_images(image, output, 0/*via linear*/, NULL); + } + + else + return logerror(output, output->tmpfile_name, + ": read of new file failed", ""); +} +#endif + +static int +testimage(Image *image, png_uint_32 opts, format_list *pf) +{ + int result; + Image copy; + + /* Copy the original data, stealing it from 'image' */ + checkopaque(image); + copy = *image; + + copy.opts = opts; + copy.buffer = NULL; + copy.bufsize = 0; + copy.allocsize = 0; + + image->input_file = NULL; + image->input_memory = NULL; + image->input_memory_size = 0; + image->tmpfile_name[0] = 0; + + { + png_uint_32 counter; + Image output; + + newimage(&output); + + result = 1; + + /* Use the low bit of 'counter' to indicate whether or not to do alpha + * removal with a background color or by composting onto the image; this + * step gets skipped if it isn't relevant + */ + for (counter=0; counter<2*FORMAT_COUNT; ++counter) + if (format_isset(pf, counter >> 1)) + { + png_uint_32 format = counter >> 1; + + png_color background_color; + png_colorp background = NULL; + + /* If there is a format change that removes the alpha channel then + * the background is relevant. If the output is 8-bit color-mapped + * then a background color *must* be provided, otherwise there are + * two tests to do - one with a color, the other with NULL. The + * NULL test happens second. + */ + if ((counter & 1) == 0) + { + if ((format & PNG_FORMAT_FLAG_ALPHA) == 0 && + (image->image.format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Alpha/transparency will be removed, the background is + * relevant: make it a color the first time + */ + random_color(&background_color); + background = &background_color; + + /* BUT if the output is to a color-mapped 8-bit format then + * the background must always be a color, so increment 'counter' + * to skip the NULL test. + */ + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && + (format & PNG_FORMAT_FLAG_LINEAR) == 0) + ++counter; + } + + /* Otherwise an alpha channel is not being eliminated, just leave + * background NULL and skip the (counter & 1) NULL test. + */ + else + ++counter; + } + /* else just use NULL for background */ + + resetimage(©); + copy.opts = opts; /* in case read_file needs to change it */ + + result = read_file(©, format, background); + if (!result) + break; + + /* Make sure the file just read matches the original file. */ + result = compare_two_images(image, ©, 0/*via linear*/, background); + if (!result) + break; + +# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED + /* Write the *copy* just made to a new file to make sure the write + * side works ok. Check the conversion to sRGB if the copy is + * linear. + */ + output.opts = opts; + result = write_one_file(&output, ©, 0/*convert to 8bit*/); + if (!result) + break; + + /* Validate against the original too; the background is needed here + * as well so that compare_two_images knows what color was used. + */ + result = compare_two_images(image, &output, 0, background); + if (!result) + break; + + if ((format & PNG_FORMAT_FLAG_LINEAR) != 0 && + (format & PNG_FORMAT_FLAG_COLORMAP) == 0) + { + /* 'output' is linear, convert to the corresponding sRGB format. + */ + output.opts = opts; + result = write_one_file(&output, ©, 1/*convert to 8bit*/); + if (!result) + break; + + /* This may involve a conversion via linear; in the ideal world + * this would round-trip correctly, but libpng 1.5.7 is not the + * ideal world so allow a drift (error_via_linear). + * + * 'image' has an alpha channel but 'output' does not then there + * will a strip-alpha-channel operation (because 'output' is + * linear), handle this by composing on black when doing the + * comparison. + */ + result = compare_two_images(image, &output, 1/*via_linear*/, + background); + if (!result) + break; + } +# endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ + } + + freeimage(&output); + } + + freeimage(©); + + return result; +} + +static int +test_one_file(const char *file_name, format_list *formats, png_uint_32 opts, + int stride_extra, int log_pass) +{ + int result; + Image image; + + newimage(&image); + initimage(&image, opts, file_name, stride_extra); + result = read_one_file(&image); + if (result) + result = testimage(&image, opts, formats); + freeimage(&image); + + /* Ensure that stderr is flushed into any log file */ + fflush(stderr); + + if (log_pass) + { + if (result) + printf("PASS:"); + + else + printf("FAIL:"); + +# ifndef PNG_SIMPLIFIED_WRITE_SUPPORTED + printf(" (no write)"); +# endif + + print_opts(opts); + printf(" %s\n", file_name); + /* stdout may not be line-buffered if it is piped to a file, so: */ + fflush(stdout); + } + + else if (!result) + exit(1); + + return result; +} + +int +main(int argc, char **argv) +{ + png_uint_32 opts = FAST_WRITE; + format_list formats; + const char *touch = NULL; + int log_pass = 0; + int redundant = 0; + int stride_extra = 0; + int retval = 0; + int c; + + init_sRGB_to_d(); +#if 0 + init_error_via_linear(); +#endif + format_init(&formats); + + for (c=1; c= sizeof tmpf) + { + fflush(stdout); + fprintf(stderr, "%s: %s is too long for a temp file prefix\n", + argv[0], argv[c]); + exit(99); + } + + /* Safe: checked above */ + strcpy(tmpf, argv[c]); + } + + else + { + fflush(stdout); + fprintf(stderr, "%s: %s requires a temporary file prefix\n", + argv[0], arg); + exit(99); + } + } + else if (strcmp(arg, "--touch") == 0) + { + if (c+1 < argc) + touch = argv[++c]; + + else + { + fflush(stdout); + fprintf(stderr, "%s: %s requires a file name argument\n", + argv[0], arg); + exit(99); + } + } + else if (arg[0] == '+') + { + png_uint_32 format = formatof(arg+1); + + if (format > FORMAT_COUNT) + exit(99); + + format_set(&formats, format); + } + else if (arg[0] == '-' && arg[1] != 0 && (arg[1] != '0' || arg[2] != 0)) + { + fflush(stdout); + fprintf(stderr, "%s: unknown option: %s\n", argv[0], arg); + exit(99); + } + else + { + if (format_is_initial(&formats)) + format_default(&formats, redundant); + + if (arg[0] == '-') + { + const int term = (arg[1] == '0' ? 0 : '\n'); + unsigned int ich = 0; + + /* Loop reading files, use a static buffer to simplify this and just + * stop if the name gets to long. + */ + static char buffer[4096]; + + do + { + int ch = getchar(); + + /* Don't allow '\0' in file names, and terminate with '\n' or, + * for -0, just '\0' (use -print0 to find to make this work!) + */ + if (ch == EOF || ch == term || ch == 0) + { + buffer[ich] = 0; + + if (ich > 0 && !test_one_file(buffer, &formats, opts, + stride_extra, log_pass)) + retval = 1; + + if (ch == EOF) + break; + + ich = 0; + --ich; /* so that the increment below sets it to 0 again */ + } + + else + buffer[ich] = (char)ch; + } while (++ich < sizeof buffer); + + if (ich) + { + buffer[32] = 0; + buffer[4095] = 0; + fprintf(stderr, "%s...%s: file name too long\n", buffer, + buffer+(4096-32)); + exit(99); + } + } + + else if (!test_one_file(arg, &formats, opts, stride_extra, log_pass)) + retval = 1; + } + } + + if (opts & ACCUMULATE) + { + unsigned int in; + + printf("static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =\n"); + printf("{\n"); + for (in=0; in<16; ++in) + { + unsigned int out; + printf(" { /* input: %s */\n ", format_names[in]); + for (out=0; out<16; ++out) + { + unsigned int alpha; + printf(" {"); + for (alpha=0; alpha<4; ++alpha) + { + printf(" %d", gpc_error[in][out][alpha]); + if (alpha < 3) putchar(','); + } + printf(" }"); + if (out < 15) + { + putchar(','); + if (out % 4 == 3) printf("\n "); + } + } + printf("\n }"); + + if (in < 15) + putchar(','); + else + putchar('\n'); + } + printf("};\n"); + + printf("static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =\n"); + printf("{\n"); + for (in=0; in<16; ++in) + { + unsigned int out; + printf(" { /* input: %s */\n ", format_names[in]); + for (out=0; out<4; ++out) + { + unsigned int alpha; + printf(" {"); + for (alpha=0; alpha<4; ++alpha) + { + printf(" %d", gpc_error_via_linear[in][out][alpha]); + if (alpha < 3) putchar(','); + } + printf(" }"); + if (out < 3) + putchar(','); + } + printf("\n }"); + + if (in < 15) + putchar(','); + else + putchar('\n'); + } + printf("};\n"); + + printf("static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =\n"); + printf("{\n"); + for (in=0; in<8; ++in) + { + unsigned int out; + printf(" { /* input: %s */\n ", format_names[in]); + for (out=0; out<8; ++out) + { + unsigned int alpha; + printf(" {"); + for (alpha=0; alpha<4; ++alpha) + { + printf(" %d", gpc_error_to_colormap[in][out][alpha]); + if (alpha < 3) putchar(','); + } + printf(" }"); + if (out < 7) + { + putchar(','); + if (out % 4 == 3) printf("\n "); + } + } + printf("\n }"); + + if (in < 7) + putchar(','); + else + putchar('\n'); + } + printf("};\n"); + } + + if (retval == 0 && touch != NULL) + { + FILE *fsuccess = fopen(touch, "wt"); + + if (fsuccess != NULL) + { + int error = 0; + fprintf(fsuccess, "PNG simple API tests succeeded\n"); + fflush(fsuccess); + error = ferror(fsuccess); + + if (fclose(fsuccess) || error) + { + fflush(stdout); + fprintf(stderr, "%s: write failed\n", touch); + exit(99); + } + } + + else + { + fflush(stdout); + fprintf(stderr, "%s: open failed\n", touch); + exit(99); + } + } + + return retval; +} + +#else /* !PNG_SIMPLIFIED_READ_SUPPORTED */ +int main(void) +{ + fprintf(stderr, "pngstest: no read support in libpng, test skipped\n"); + /* So the test is skipped: */ + return 77; +} +#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngunknown.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngunknown.c new file mode 100644 index 00000000000..25452dbc950 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngunknown.c @@ -0,0 +1,1066 @@ + +/* pngunknown.c - test the read side unknown chunk handling + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 2013 Glenn Randers-Pehrson + * Written by John Cunningham Bowler + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * NOTES: + * This is a C program that is intended to be linked against libpng. It + * allows the libpng unknown handling code to be tested by interpreting + * arguments to save or discard combinations of chunks. The program is + * currently just a minimal validation for the built-in libpng facilities. + */ + +#include +#include +#include +#include + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +#ifdef PNG_READ_SUPPORTED + +#if PNG_LIBPNG_VER < 10500 +/* This deliberately lacks the PNG_CONST. */ +typedef png_byte *png_const_bytep; + +/* This is copied from 1.5.1 png.h: */ +#define PNG_INTERLACE_ADAM7_PASSES 7 +#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7) +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) +#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ + (((yIn)<>(((7-(off))-(pass))<<2)) & 0xFU) | \ + ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U)) +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +/* These are needed too for the default build: */ +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED + +/* This comes from pnglibconf.h afer 1.5: */ +#define PNG_FP_1 100000 +#define PNG_GAMMA_THRESHOLD_FIXED\ + ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) +#endif + +#if PNG_LIBPNG_VER < 10600 + /* 1.6.0 constifies many APIs. The following exists to allow pngvalid to be + * compiled against earlier versions. + */ +# define png_const_structp png_structp +#endif + + +/* Copied from pngpriv.h */ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_CHUNK(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +#define png_IHDR PNG_CHUNK( 73, 72, 68, 82) +#define png_IDAT PNG_CHUNK( 73, 68, 65, 84) +#define png_IEND PNG_CHUNK( 73, 69, 78, 68) +#define png_PLTE PNG_CHUNK( 80, 76, 84, 69) +#define png_bKGD PNG_CHUNK( 98, 75, 71, 68) +#define png_cHRM PNG_CHUNK( 99, 72, 82, 77) +#define png_gAMA PNG_CHUNK(103, 65, 77, 65) +#define png_hIST PNG_CHUNK(104, 73, 83, 84) +#define png_iCCP PNG_CHUNK(105, 67, 67, 80) +#define png_iTXt PNG_CHUNK(105, 84, 88, 116) +#define png_oFFs PNG_CHUNK(111, 70, 70, 115) +#define png_pCAL PNG_CHUNK(112, 67, 65, 76) +#define png_sCAL PNG_CHUNK(115, 67, 65, 76) +#define png_pHYs PNG_CHUNK(112, 72, 89, 115) +#define png_sBIT PNG_CHUNK(115, 66, 73, 84) +#define png_sPLT PNG_CHUNK(115, 80, 76, 84) +#define png_sRGB PNG_CHUNK(115, 82, 71, 66) +#define png_sTER PNG_CHUNK(115, 84, 69, 82) +#define png_tEXt PNG_CHUNK(116, 69, 88, 116) +#define png_tIME PNG_CHUNK(116, 73, 77, 69) +#define png_tRNS PNG_CHUNK(116, 82, 78, 83) +#define png_zTXt PNG_CHUNK(122, 84, 88, 116) +#define png_vpAg PNG_CHUNK('v', 'p', 'A', 'g') + +/* Test on flag values as defined in the spec (section 5.4): */ +#define PNG_CHUNK_ANCILLARY(c ) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) +#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) +#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) +#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) + +/* Chunk information */ +#define PNG_INFO_tEXt 0x10000000U +#define PNG_INFO_iTXt 0x20000000U +#define PNG_INFO_zTXt 0x40000000U + +#define PNG_INFO_sTER 0x01000000U +#define PNG_INFO_vpAg 0x02000000U + +#define ABSENT 0 +#define START 1 +#define END 2 + +static struct +{ + char name[5]; + png_uint_32 flag; + png_uint_32 tag; + int unknown; /* Chunk not known to libpng */ + int all; /* Chunk set by the '-1' option */ + int position; /* position in pngtest.png */ + int keep; /* unknown handling setting */ +} chunk_info[] = { + /* Critical chunks */ + { "IDAT", PNG_INFO_IDAT, png_IDAT, 0, 0, START, 0 }, /* must be [0] */ + { "PLTE", PNG_INFO_PLTE, png_PLTE, 0, 0, ABSENT, 0 }, + + /* Non-critical chunks that libpng handles */ + /* This is a mess but it seems to be the only way to do it - there is no way to + * check for definition outside a #if. + */ + { "bKGD", PNG_INFO_bKGD, png_bKGD, +# ifdef PNG_READ_bKGD_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "cHRM", PNG_INFO_cHRM, png_cHRM, +# ifdef PNG_READ_cHRM_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "gAMA", PNG_INFO_gAMA, png_gAMA, +# ifdef PNG_READ_gAMA_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "hIST", PNG_INFO_hIST, png_hIST, +# ifdef PNG_READ_hIST_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "iCCP", PNG_INFO_iCCP, png_iCCP, +# ifdef PNG_READ_iCCP_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "iTXt", PNG_INFO_iTXt, png_iTXt, +# ifdef PNG_READ_iTXt_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "oFFs", PNG_INFO_oFFs, png_oFFs, +# ifdef PNG_READ_oFFs_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "pCAL", PNG_INFO_pCAL, png_pCAL, +# ifdef PNG_READ_pCAL_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "pHYs", PNG_INFO_pHYs, png_pHYs, +# ifdef PNG_READ_pHYs_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "sBIT", PNG_INFO_sBIT, png_sBIT, +# ifdef PNG_READ_sBIT_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "sCAL", PNG_INFO_sCAL, png_sCAL, +# ifdef PNG_READ_sCAL_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "sPLT", PNG_INFO_sPLT, png_sPLT, +# ifdef PNG_READ_sPLT_SUPPORTED + 0, +# else + 1, +# endif + 1, ABSENT, 0 }, + { "sRGB", PNG_INFO_sRGB, png_sRGB, +# ifdef PNG_READ_sRGB_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "tEXt", PNG_INFO_tEXt, png_tEXt, +# ifdef PNG_READ_tEXt_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "tIME", PNG_INFO_tIME, png_tIME, +# ifdef PNG_READ_tIME_SUPPORTED + 0, +# else + 1, +# endif + 1, START, 0 }, + { "tRNS", PNG_INFO_tRNS, png_tRNS, +# ifdef PNG_READ_tRNS_SUPPORTED + 0, +# else + 1, +# endif + 0, ABSENT, 0 }, + { "zTXt", PNG_INFO_zTXt, png_zTXt, +# ifdef PNG_READ_zTXt_SUPPORTED + 0, +# else + 1, +# endif + 1, END, 0 }, + + /* No libpng handling */ + { "sTER", PNG_INFO_sTER, png_sTER, 1, 1, START, 0 }, + { "vpAg", PNG_INFO_vpAg, png_vpAg, 1, 0, START, 0 }, +}; + +#define NINFO ((int)((sizeof chunk_info)/(sizeof chunk_info[0]))) + +static void +clear_keep(void) +{ + int i = NINFO; + while (--i >= 0) + chunk_info[i].keep = 0; +} + +static int +find(const char *name) +{ + int i = NINFO; + while (--i >= 0) + { + if (memcmp(chunk_info[i].name, name, 4) == 0) + break; + } + + return i; +} + +static int +findb(const png_byte *name) +{ + int i = NINFO; + while (--i >= 0) + { + if (memcmp(chunk_info[i].name, name, 4) == 0) + break; + } + + return i; +} + +static int +find_by_flag(png_uint_32 flag) +{ + int i = NINFO; + + while (--i >= 0) if (chunk_info[i].flag == flag) return i; + + fprintf(stderr, "pngunknown: internal error\n"); + exit(4); +} + +static int +ancillary(const char *name) +{ + return PNG_CHUNK_ANCILLARY(PNG_CHUNK(name[0], name[1], name[2], name[3])); +} + +static int +ancillaryb(const png_byte *name) +{ + return PNG_CHUNK_ANCILLARY(PNG_CHUNK(name[0], name[1], name[2], name[3])); +} + +/* Type of an error_ptr */ +typedef struct +{ + jmp_buf error_return; + png_structp png_ptr; + png_infop info_ptr, end_ptr; + int error_count; + int warning_count; + const char *program; + const char *file; + const char *test; +} display; + +static const char init[] = "initialization"; +static const char cmd[] = "command line"; + +static void +init_display(display *d, const char *program) +{ + memset(d, 0, sizeof *d); + d->png_ptr = NULL; + d->info_ptr = d->end_ptr = NULL; + d->error_count = d->warning_count = 0; + d->program = program; + d->file = program; + d->test = init; +} + +static void +clean_display(display *d) +{ + png_destroy_read_struct(&d->png_ptr, &d->info_ptr, &d->end_ptr); + + /* This must not happen - it might cause an app crash */ + if (d->png_ptr != NULL || d->info_ptr != NULL || d->end_ptr != NULL) + { + fprintf(stderr, "%s(%s): png_destroy_read_struct error\n", d->file, + d->test); + exit(1); + } + + /* Invalidate the test */ + d->test = init; +} + +PNG_FUNCTION(void, display_exit, (display *d), static PNG_NORETURN) +{ + ++(d->error_count); + + if (d->png_ptr != NULL) + clean_display(d); + + /* During initialization and if this is a single command line argument set + * exit now - there is only one test, otherwise longjmp to do the next test. + */ + if (d->test == init || d->test == cmd) + exit(1); + + longjmp(d->error_return, 1); +} + +static int +display_rc(const display *d, int strict) +{ + return d->error_count + (strict ? d->warning_count : 0); +} + +/* libpng error and warning callbacks */ +PNG_FUNCTION(void, error, (png_structp png_ptr, const char *message), + static PNG_NORETURN) +{ + display *d = (display*)png_get_error_ptr(png_ptr); + + fprintf(stderr, "%s(%s): libpng error: %s\n", d->file, d->test, message); + display_exit(d); +} + +static void +warning(png_structp png_ptr, const char *message) +{ + display *d = (display*)png_get_error_ptr(png_ptr); + + fprintf(stderr, "%s(%s): libpng warning: %s\n", d->file, d->test, message); + ++(d->warning_count); +} + +static png_uint_32 +get_valid(display *d, png_infop info_ptr) +{ + png_uint_32 flags = png_get_valid(d->png_ptr, info_ptr, (png_uint_32)~0); + + /* Map the text chunks back into the flags */ + { + png_textp text; + png_uint_32 ntext = png_get_text(d->png_ptr, info_ptr, &text, NULL); + + while (ntext-- > 0) switch (text[ntext].compression) + { + case -1: + flags |= PNG_INFO_tEXt; + break; + case 0: + flags |= PNG_INFO_zTXt; + break; + case 1: + case 2: + flags |= PNG_INFO_iTXt; + break; + default: + fprintf(stderr, "%s(%s): unknown text compression %d\n", d->file, + d->test, text[ntext].compression); + display_exit(d); + } + } + + return flags; +} + +static png_uint_32 +get_unknown(display *d, int def, png_infop info_ptr) +{ + /* Create corresponding 'unknown' flags */ + png_uint_32 flags = 0; + { + png_unknown_chunkp unknown; + int num_unknown = png_get_unknown_chunks(d->png_ptr, info_ptr, &unknown); + + while (--num_unknown >= 0) + { + int chunk = findb(unknown[num_unknown].name); + + /* Chunks not known to pngunknown must be validated here; since they + * must also be unknown to libpng the 'def' behavior should have been + * used. + */ + if (chunk < 0) switch (def) + { + default: /* impossible */ + case PNG_HANDLE_CHUNK_AS_DEFAULT: + case PNG_HANDLE_CHUNK_NEVER: + fprintf(stderr, "%s(%s): %s: %s: unknown chunk saved\n", + d->file, d->test, def ? "discard" : "default", + unknown[num_unknown].name); + ++(d->error_count); + break; + + case PNG_HANDLE_CHUNK_IF_SAFE: + if (!ancillaryb(unknown[num_unknown].name)) + { + fprintf(stderr, + "%s(%s): if-safe: %s: unknown critical chunk saved\n", + d->file, d->test, unknown[num_unknown].name); + ++(d->error_count); + break; + } + /* FALL THROUGH (safe) */ + case PNG_HANDLE_CHUNK_ALWAYS: + break; + } + + else + flags |= chunk_info[chunk].flag; + } + } + + return flags; +} + +static int +check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, + display *d) +{ + int i, def = PNG_HANDLE_CHUNK_AS_DEFAULT, npasses, ipass; + png_uint_32 height; + + /* Some of these errors are permanently fatal and cause an exit here, others + * are per-test and cause an error return. + */ + d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, d, error, + warning); + if (d->png_ptr == NULL) + { + fprintf(stderr, "%s(%s): could not allocate png struct\n", d->file, + d->test); + /* Terminate here, this error is not test specific. */ + exit(1); + } + + d->info_ptr = png_create_info_struct(d->png_ptr); + d->end_ptr = png_create_info_struct(d->png_ptr); + if (d->info_ptr == NULL || d->end_ptr == NULL) + { + fprintf(stderr, "%s(%s): could not allocate png info\n", d->file, + d->test); + clean_display(d); + exit(1); + } + + png_init_io(d->png_ptr, fp); + + /* Handle each argument in turn; multiple settings are possible for the same + * chunk and multiple calls will occur (the last one should override all + * preceding ones). + */ + for (i=0; ipng_ptr, option, name, 1); + chunk_info[chunk].keep = option; +# endif + continue; + } + + break; + + case 7: /* default */ + if (memcmp(argv[i], "default", 7) == 0) + { +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0); +# endif + def = option; + continue; + } + + break; + + case 3: /* all */ + if (memcmp(argv[i], "all", 3) == 0) + { +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1); + def = option; + + for (chunk = 0; chunk < NINFO; ++chunk) + if (chunk_info[chunk].all) + chunk_info[chunk].keep = option; +# endif + continue; + } + + break; + + default: /* some misplaced = */ + + break; + } + } + + fprintf(stderr, "%s(%s): %s: unrecognized chunk argument\n", d->file, + d->test, argv[i]); + display_exit(d); + } + + png_read_info(d->png_ptr, d->info_ptr); + + switch (png_get_interlace_type(d->png_ptr, d->info_ptr)) + { + case PNG_INTERLACE_NONE: + npasses = 1; + break; + + case PNG_INTERLACE_ADAM7: + npasses = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + /* Hard error because it is not test specific */ + fprintf(stderr, "%s(%s): invalid interlace type\n", d->file, d->test); + clean_display(d); + exit(1); + } + + /* Skip the image data, if IDAT is not being handled then don't do this + * because it will cause a CRC error. + */ + if (chunk_info[0/*IDAT*/].keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + { + png_start_read_image(d->png_ptr); + height = png_get_image_height(d->png_ptr, d->info_ptr); + + if (npasses > 1) + { + png_uint_32 width = png_get_image_width(d->png_ptr, d->info_ptr); + + for (ipass=0; ipass 0) + { + png_uint_32 y; + + for (y=0; ypng_ptr, NULL, NULL); + } + } + } /* interlaced */ + + else /* not interlaced */ + { + png_uint_32 y; + + for (y=0; ypng_ptr, NULL, NULL); + } + } + + png_read_end(d->png_ptr, d->end_ptr); + + flags[0] = get_valid(d, d->info_ptr); + flags[1] = get_unknown(d, def, d->info_ptr); + + /* Only png_read_png sets PNG_INFO_IDAT! */ + flags[chunk_info[0/*IDAT*/].keep != PNG_HANDLE_CHUNK_AS_DEFAULT] |= + PNG_INFO_IDAT; + + flags[2] = get_valid(d, d->end_ptr); + flags[3] = get_unknown(d, def, d->end_ptr); + + clean_display(d); + + return def; +} + +static void +check_error(display *d, png_uint_32 flags, const char *message) +{ + while (flags) + { + png_uint_32 flag = flags & -(png_int_32)flags; + int i = find_by_flag(flag); + + fprintf(stderr, "%s(%s): chunk %s: %s\n", d->file, d->test, + chunk_info[i].name, message); + ++(d->error_count); + + flags &= ~flag; + } +} + +static void +check_handling(display *d, int def, png_uint_32 chunks, png_uint_32 known, + png_uint_32 unknown, const char *position) +{ + while (chunks) + { + png_uint_32 flag = chunks & -(png_int_32)chunks; + int i = find_by_flag(flag); + int keep = chunk_info[i].keep; + const char *type; + const char *errorx = NULL; + + if (chunk_info[i].unknown) + { + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + { + type = "UNKNOWN (default)"; + keep = def; + } + + else + type = "UNKNOWN (specified)"; + + if (flag & known) + errorx = "chunk processed"; + + else switch (keep) + { + case PNG_HANDLE_CHUNK_AS_DEFAULT: + if (flag & unknown) + errorx = "DEFAULT: unknown chunk saved"; + break; + + case PNG_HANDLE_CHUNK_NEVER: + if (flag & unknown) + errorx = "DISCARD: unknown chunk saved"; + break; + + case PNG_HANDLE_CHUNK_IF_SAFE: + if (ancillary(chunk_info[i].name)) + { + if (!(flag & unknown)) + errorx = "IF-SAFE: unknown ancillary chunk lost"; + } + + else if (flag & unknown) + errorx = "IF-SAFE: unknown critical chunk saved"; + break; + + case PNG_HANDLE_CHUNK_ALWAYS: + if (!(flag & unknown)) + errorx = "SAVE: unknown chunk lost"; + break; + + default: + errorx = "internal error: bad keep"; + break; + } + } /* unknown chunk */ + + else /* known chunk */ + { + type = "KNOWN"; + + if (flag & known) + { + /* chunk was processed, it won't have been saved because that is + * caught below when checking for inconsistent processing. + */ + if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT) + errorx = "!DEFAULT: known chunk processed"; + } + + else /* not processed */ switch (keep) + { + case PNG_HANDLE_CHUNK_AS_DEFAULT: + errorx = "DEFAULT: known chunk not processed"; + break; + + case PNG_HANDLE_CHUNK_NEVER: + if (flag & unknown) + errorx = "DISCARD: known chunk saved"; + break; + + case PNG_HANDLE_CHUNK_IF_SAFE: + if (ancillary(chunk_info[i].name)) + { + if (!(flag & unknown)) + errorx = "IF-SAFE: known ancillary chunk lost"; + } + + else if (flag & unknown) + errorx = "IF-SAFE: known critical chunk saved"; + break; + + case PNG_HANDLE_CHUNK_ALWAYS: + if (!(flag & unknown)) + errorx = "SAVE: known chunk lost"; + break; + + default: + errorx = "internal error: bad keep (2)"; + break; + } + } + + if (errorx != NULL) + { + ++(d->error_count); + fprintf(stderr, "%s(%s): %s %s %s: %s\n", + d->file, d->test, type, chunk_info[i].name, position, errorx); + } + + chunks &= ~flag; + } +} + +static void +perform_one_test(FILE *fp, int argc, const char **argv, + png_uint_32 *default_flags, display *d) +{ + int def; + png_uint_32 flags[2][4]; + + rewind(fp); + clear_keep(); + memcpy(flags[0], default_flags, sizeof flags[0]); + + def = check(fp, argc, argv, flags[1], d); + + /* Chunks should either be known or unknown, never both and this should apply + * whether the chunk is before or after the IDAT (actually, the app can + * probably change this by swapping the handling after the image, but this + * test does not do that.) + */ + check_error(d, (flags[0][0]|flags[0][2]) & (flags[0][1]|flags[0][3]), + "chunk handled inconsistently in count tests"); + check_error(d, (flags[1][0]|flags[1][2]) & (flags[1][1]|flags[1][3]), + "chunk handled inconsistently in option tests"); + + /* Now find out what happened to each chunk before and after the IDAT and + * determine if the behavior was correct. First some basic sanity checks, + * any known chunk should be known in the original count, any unknown chunk + * should be either known or unknown in the original. + */ + { + png_uint_32 test; + + test = flags[1][0] & ~flags[0][0]; + check_error(d, test, "new known chunk before IDAT"); + test = flags[1][1] & ~(flags[0][0] | flags[0][1]); + check_error(d, test, "new unknown chunk before IDAT"); + test = flags[1][2] & ~flags[0][2]; + check_error(d, test, "new known chunk after IDAT"); + test = flags[1][3] & ~(flags[0][2] | flags[0][3]); + check_error(d, test, "new unknown chunk after IDAT"); + } + + /* Now each chunk in the original list should have been handled according to + * the options set for that chunk, regardless of whether libpng knows about + * it or not. + */ + check_handling(d, def, flags[0][0] | flags[0][1], flags[1][0], flags[1][1], + "before IDAT"); + check_handling(d, def, flags[0][2] | flags[0][3], flags[1][2], flags[1][3], + "after IDAT"); +} + +static void +perform_one_test_safe(FILE *fp, int argc, const char **argv, + png_uint_32 *default_flags, display *d, const char *test) +{ + if (setjmp(d->error_return) == 0) + { + d->test = test; /* allow use of d->error_return */ + perform_one_test(fp, argc, argv, default_flags, d); + d->test = init; /* prevent use of d->error_return */ + } +} + +static const char *standard_tests[] = +{ + "discard", "default=discard", 0, + "save", "default=save", 0, + "if-safe", "default=if-safe", 0, + "vpAg", "vpAg=if-safe", 0, + "sTER", "sTER=if-safe", 0, + "IDAT", "default=discard", "IDAT=save", 0, + "sAPI", "bKGD=save", "cHRM=save", "gAMA=save", "all=discard", "iCCP=save", + "sBIT=save", "sRGB=save", 0, + 0/*end*/ +}; + +static PNG_NORETURN void +usage(const char *program, const char *reason) +{ + fprintf(stderr, "pngunknown: %s: usage:\n %s [--strict] " + "--default|{(CHNK|default|all)=(default|discard|if-safe|save)} " + "testfile.png\n", reason, program); + exit(2); +} + +int +main(int argc, const char **argv) +{ + FILE *fp; + png_uint_32 default_flags[4/*valid,unknown{before,after}*/]; + int strict = 0, default_tests = 0; + const char *count_argv = "default=save"; + const char *touch_file = NULL; + display d; + + init_display(&d, argv[0]); + + while (++argv, --argc > 0) + { + if (strcmp(*argv, "--strict") == 0) + strict = 1; + + else if (strcmp(*argv, "--default") == 0) + default_tests = 1; + + else if (strcmp(*argv, "--touch") == 0) + { + if (argc > 1) + touch_file = *++argv, --argc; + + else + usage(d.program, "--touch: missing file name"); + } + + else + break; + } + + /* A file name is required, but there should be no other arguments if + * --default was specified. + */ + if (argc <= 0) + usage(d.program, "missing test file"); + + /* GCC BUG: if (default_tests && argc != 1) triggers some weird GCC argc + * optimization which causes warnings with -Wstrict-overflow! + */ + else if (default_tests) if (argc != 1) + usage(d.program, "extra arguments"); + +# ifndef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + fprintf(stderr, "%s: warning: no 'save' support so arguments ignored\n", + d.program); +# endif + + /* The name of the test file is the last argument; remove it. */ + d.file = argv[--argc]; + + fp = fopen(d.file, "rb"); + if (fp == NULL) + { + perror(d.file); + exit(2); + } + + /* First find all the chunks, known and unknown, in the test file, a failure + * here aborts the whole test. + */ + if (check(fp, 1, &count_argv, default_flags, &d) != + PNG_HANDLE_CHUNK_ALWAYS) + { + fprintf(stderr, "%s: %s: internal error\n", d.program, d.file); + exit(3); + } + + /* Now find what the various supplied options cause to change: */ + if (!default_tests) + { + d.test = cmd; /* acts as a flag to say exit, do not longjmp */ + perform_one_test(fp, argc, argv, default_flags, &d); + d.test = init; + } + + else + { + const char **test = standard_tests; + + /* Set the exit_test pointer here so we can continue after a libpng error. + * NOTE: this leaks memory because the png_struct data from the failing + * test is never freed. + */ + while (*test) + { + const char *this_test = *test++; + const char **next = test; + int count = display_rc(&d, strict), new_count; + const char *result; + int arg_count = 0; + + while (*next) ++next, ++arg_count; + + perform_one_test_safe(fp, arg_count, test, default_flags, &d, + this_test); + + new_count = display_rc(&d, strict); + + if (new_count == count) + result = "PASS"; + + else + result = "FAIL"; + + printf("%s: %s %s\n", result, d.program, this_test); + + test = next+1; + } + } + + fclose(fp); + + if (display_rc(&d, strict) == 0) + { + /* Success, touch the success file if appropriate */ + if (touch_file != NULL) + { + FILE *fsuccess = fopen(touch_file, "wt"); + + if (fsuccess != NULL) + { + int err = 0; + fprintf(fsuccess, "PNG unknown tests succeeded\n"); + fflush(fsuccess); + err = ferror(fsuccess); + + if (fclose(fsuccess) || err) + { + fprintf(stderr, "%s: write failed\n", touch_file); + exit(1); + } + } + + else + { + fprintf(stderr, "%s: open failed\n", touch_file); + exit(1); + } + } + + return 0; + } + + return 1; +} + +#else +int +main(void) +{ + fprintf(stderr, + " test ignored because libpng was not built with unknown chunk support\n"); + /* So the test is skipped: */ + return 77; +} +#endif diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngvalid.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngvalid.c new file mode 100644 index 00000000000..fbd6778cf36 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/pngvalid.c @@ -0,0 +1,10145 @@ + +/* pngvalid.c - validate libpng by constructing then reading png files. + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 2013 Glenn Randers-Pehrson + * Written by John Cunningham Bowler + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * NOTES: + * This is a C program that is intended to be linked against libpng. It + * generates bitmaps internally, stores them as PNG files (using the + * sequential write code) then reads them back (using the sequential + * read code) and validates that the result has the correct data. + * + * The program can be modified and extended to test the correctness of + * transformations performed by libpng. + */ + +#define _POSIX_SOURCE 1 +#define _ISOC99_SOURCE 1 /* For floating point */ +#define _GNU_SOURCE 1 /* For the floating point exception extension */ + +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +#ifdef HAVE_FEENABLEEXCEPT /* from config.h, if included */ +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +#ifdef PNG_WRITE_SUPPORTED /* else pngvalid can do nothing */ + +#if PNG_LIBPNG_VER < 10500 +/* This deliberately lacks the PNG_CONST. */ +typedef png_byte *png_const_bytep; + +/* This is copied from 1.5.1 png.h: */ +#define PNG_INTERLACE_ADAM7_PASSES 7 +#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7) +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) +#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ + (((yIn)<>(((7-(off))-(pass))<<2)) & 0xFU) | \ + ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U)) +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +/* These are needed too for the default build: */ +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED + +/* This comes from pnglibconf.h afer 1.5: */ +#define PNG_FP_1 100000 +#define PNG_GAMMA_THRESHOLD_FIXED\ + ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) +#endif + +#if PNG_LIBPNG_VER < 10600 + /* 1.6.0 constifies many APIs, the following exists to allow pngvalid to be + * compiled against earlier versions. + */ +# define png_const_structp png_structp +#endif + +#include /* For crc32 */ + +#include /* For floating point constants */ +#include /* For malloc */ +#include /* For memcpy, memset */ +#include /* For floor */ + +/* Unused formal parameter errors are removed using the following macro which is + * expected to have no bad effects on performance. + */ +#ifndef UNUSED +# if defined(__GNUC__) || defined(_MSC_VER) +# define UNUSED(param) (void)param; +# else +# define UNUSED(param) +# endif +#endif + +/***************************** EXCEPTION HANDLING *****************************/ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../visupng/cexcept.h" +#endif + +#ifdef __cplusplus +# define this not_the_cpp_this +# define new not_the_cpp_new +# define voidcast(type, value) static_cast(value) +#else +# define voidcast(type, value) (value) +#endif /* __cplusplus */ + +struct png_store; +define_exception_type(struct png_store*); + +/* The following are macros to reduce typing everywhere where the well known + * name 'the_exception_context' must be defined. + */ +#define anon_context(ps) struct exception_context *the_exception_context = \ + &(ps)->exception_context +#define context(ps,fault) anon_context(ps); png_store *fault + +/******************************* UTILITIES ************************************/ +/* Error handling is particularly problematic in production code - error + * handlers often themselves have bugs which lead to programs that detect + * minor errors crashing. The following functions deal with one very + * common class of errors in error handlers - attempting to format error or + * warning messages into buffers that are too small. + */ +static size_t safecat(char *buffer, size_t bufsize, size_t pos, + PNG_CONST char *cat) +{ + while (pos < bufsize && cat != NULL && *cat != 0) + buffer[pos++] = *cat++; + + if (pos >= bufsize) + pos = bufsize-1; + + buffer[pos] = 0; + return pos; +} + +static size_t safecatn(char *buffer, size_t bufsize, size_t pos, int n) +{ + char number[64]; + sprintf(number, "%d", n); + return safecat(buffer, bufsize, pos, number); +} + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +static size_t safecatd(char *buffer, size_t bufsize, size_t pos, double d, + int precision) +{ + char number[64]; + sprintf(number, "%.*f", precision, d); + return safecat(buffer, bufsize, pos, number); +} +#endif + +static PNG_CONST char invalid[] = "invalid"; +static PNG_CONST char sep[] = ": "; + +static PNG_CONST char *colour_types[8] = +{ + "grayscale", invalid, "truecolour", "indexed-colour", + "grayscale with alpha", invalid, "truecolour with alpha", invalid +}; + +#ifdef PNG_READ_SUPPORTED +/* Convert a double precision value to fixed point. */ +static png_fixed_point +fix(double d) +{ + d = floor(d * PNG_FP_1 + .5); + return (png_fixed_point)d; +} +#endif /* PNG_READ_SUPPORTED */ + +/* Generate random bytes. This uses a boring repeatable algorithm and it + * is implemented here so that it gives the same set of numbers on every + * architecture. It's a linear congruential generator (Knuth or Sedgewick + * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and + * Hill, "The Art of Electronics" (Pseudo-Random Bit Sequences and Noise + * Generation.) + */ +static void +make_random_bytes(png_uint_32* seed, void* pv, size_t size) +{ + png_uint_32 u0 = seed[0], u1 = seed[1]; + png_bytep bytes = voidcast(png_bytep, pv); + + /* There are thirty three bits, the next bit in the sequence is bit-33 XOR + * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. + */ + size_t i; + for (i=0; i> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; + u1 <<= 8; + u1 |= u0 >> 24; + u0 <<= 8; + u0 |= u; + *bytes++ = (png_byte)u; + } + + seed[0] = u0; + seed[1] = u1; +} + +static void +make_four_random_bytes(png_uint_32* seed, png_bytep bytes) +{ + make_random_bytes(seed, bytes, 4); +} + +#ifdef PNG_READ_SUPPORTED +static void +randomize(void *pv, size_t size) +{ + static png_uint_32 random_seed[2] = {0x56789abc, 0xd}; + make_random_bytes(random_seed, pv, size); +} + +#define RANDOMIZE(this) randomize(&(this), sizeof (this)) + +static unsigned int +random_mod(unsigned int max) +{ + unsigned int x; + + RANDOMIZE(x); + + return x % max; /* 0 .. max-1 */ +} + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +static int +random_choice(void) +{ + unsigned char x; + + RANDOMIZE(x); + + return x & 1; +} +#endif +#endif /* PNG_READ_SUPPORTED */ + +/* A numeric ID based on PNG file characteristics. The 'do_interlace' field + * simply records whether pngvalid did the interlace itself or whether it + * was done by libpng. Width and height must be less than 256. 'palette' is an + * index of the palette to use for formats with a palette (0 otherwise.) + */ +#define FILEID(col, depth, palette, interlace, width, height, do_interlace) \ + ((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \ + (((do_interlace)!=0)<<15) + ((width)<<16) + ((height)<<24))) + +#define COL_FROM_ID(id) ((png_byte)((id)& 0x7U)) +#define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU)) +#define PALETTE_FROM_ID(id) (((id) >> 8) & 0x1f) +#define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3)) +#define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1)) +#define WIDTH_FROM_ID(id) (((id)>>16) & 0xff) +#define HEIGHT_FROM_ID(id) (((id)>>24) & 0xff) + +/* Utility to construct a standard name for a standard image. */ +static size_t +standard_name(char *buffer, size_t bufsize, size_t pos, png_byte colour_type, + int bit_depth, unsigned int npalette, int interlace_type, + png_uint_32 w, png_uint_32 h, int do_interlace) +{ + pos = safecat(buffer, bufsize, pos, colour_types[colour_type]); + if (npalette > 0) + { + pos = safecat(buffer, bufsize, pos, "["); + pos = safecatn(buffer, bufsize, pos, npalette); + pos = safecat(buffer, bufsize, pos, "]"); + } + pos = safecat(buffer, bufsize, pos, " "); + pos = safecatn(buffer, bufsize, pos, bit_depth); + pos = safecat(buffer, bufsize, pos, " bit"); + + if (interlace_type != PNG_INTERLACE_NONE) + { + pos = safecat(buffer, bufsize, pos, " interlaced"); + if (do_interlace) + pos = safecat(buffer, bufsize, pos, "(pngvalid)"); + else + pos = safecat(buffer, bufsize, pos, "(libpng)"); + } + + if (w > 0 || h > 0) + { + pos = safecat(buffer, bufsize, pos, " "); + pos = safecatn(buffer, bufsize, pos, w); + pos = safecat(buffer, bufsize, pos, "x"); + pos = safecatn(buffer, bufsize, pos, h); + } + + return pos; +} + +static size_t +standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id) +{ + return standard_name(buffer, bufsize, pos, COL_FROM_ID(id), + DEPTH_FROM_ID(id), PALETTE_FROM_ID(id), INTERLACE_FROM_ID(id), + WIDTH_FROM_ID(id), HEIGHT_FROM_ID(id), DO_INTERLACE_FROM_ID(id)); +} + +/* Convenience API and defines to list valid formats. Note that 16 bit read and + * write support is required to do 16 bit read tests (we must be able to make a + * 16 bit image to test!) + */ +#ifdef PNG_WRITE_16BIT_SUPPORTED +# define WRITE_BDHI 4 +# ifdef PNG_READ_16BIT_SUPPORTED +# define READ_BDHI 4 +# define DO_16BIT +# endif +#else +# define WRITE_BDHI 3 +#endif +#ifndef DO_16BIT +# define READ_BDHI 3 +#endif + +/* The following defines the number of different palettes to generate for + * each log bit depth of a colour type 3 standard image. + */ +#define PALETTE_COUNT(bit_depth) ((bit_depth) > 4 ? 1U : 16U) + +static int +next_format(png_bytep colour_type, png_bytep bit_depth, + unsigned int* palette_number) +{ + if (*bit_depth == 0) + { + *colour_type = 0, *bit_depth = 1, *palette_number = 0; + return 1; + } + + if (*colour_type == 3) + { + /* Add multiple palettes for colour type 3. */ + if (++*palette_number < PALETTE_COUNT(*bit_depth)) + return 1; + + *palette_number = 0; + } + + *bit_depth = (png_byte)(*bit_depth << 1); + + /* Palette images are restricted to 8 bit depth */ + if (*bit_depth <= 8 +# ifdef DO_16BIT + || (*colour_type != 3 && *bit_depth <= 16) +# endif + ) + return 1; + + /* Move to the next color type, or return 0 at the end. */ + switch (*colour_type) + { + case 0: + *colour_type = 2; + *bit_depth = 8; + return 1; + + case 2: + *colour_type = 3; + *bit_depth = 1; + return 1; + + case 3: + *colour_type = 4; + *bit_depth = 8; + return 1; + + case 4: + *colour_type = 6; + *bit_depth = 8; + return 1; + + default: + return 0; + } +} + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +static unsigned int +sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth, + png_uint_32 x, unsigned int sample_index) +{ + png_uint_32 bit_index, result; + + /* Find a sample index for the desired sample: */ + x *= bit_depth; + bit_index = x; + + if ((colour_type & 1) == 0) /* !palette */ + { + if (colour_type & 2) + bit_index *= 3; + + if (colour_type & 4) + bit_index += x; /* Alpha channel */ + + /* Multiple channels; select one: */ + if (colour_type & (2+4)) + bit_index += sample_index * bit_depth; + } + + /* Return the sample from the row as an integer. */ + row += bit_index >> 3; + result = *row; + + if (bit_depth == 8) + return result; + + else if (bit_depth > 8) + return (result << 8) + *++row; + + /* Less than 8 bits per sample. */ + bit_index &= 7; + return (result >> (8-bit_index-bit_depth)) & ((1U<> 3] & ~destMask; + unsigned int sourceByte = fromBuffer[fromIndex >> 3]; + + /* Don't rely on << or >> supporting '0' here, just in case: */ + fromIndex &= 7; + if (fromIndex > 0) sourceByte <<= fromIndex; + if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7; + + toBuffer[toIndex >> 3] = (png_byte)(destByte | (sourceByte & destMask)); + } + else /* One or more bytes */ + memmove(toBuffer+(toIndex>>3), fromBuffer+(fromIndex>>3), pixelSize>>3); +} + +#ifdef PNG_READ_SUPPORTED +/* Copy a complete row of pixels, taking into account potential partial + * bytes at the end. + */ +static void +row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth) +{ + memcpy(toBuffer, fromBuffer, bitWidth >> 3); + + if ((bitWidth & 7) != 0) + { + unsigned int mask; + + toBuffer += bitWidth >> 3; + fromBuffer += bitWidth >> 3; + /* The remaining bits are in the top of the byte, the mask is the bits to + * retain. + */ + mask = 0xff >> (bitWidth & 7); + *toBuffer = (png_byte)((*toBuffer & mask) | (*fromBuffer & ~mask)); + } +} + +/* Compare pixels - they are assumed to start at the first byte in the + * given buffers. + */ +static int +pixel_cmp(png_const_bytep pa, png_const_bytep pb, png_uint_32 bit_width) +{ +#if PNG_LIBPNG_VER < 10506 + if (memcmp(pa, pb, bit_width>>3) == 0) + { + png_uint_32 p; + + if ((bit_width & 7) == 0) return 0; + + /* Ok, any differences? */ + p = pa[bit_width >> 3]; + p ^= pb[bit_width >> 3]; + + if (p == 0) return 0; + + /* There are, but they may not be significant, remove the bits + * after the end (the low order bits in PNG.) + */ + bit_width &= 7; + p >>= 8-bit_width; + + if (p == 0) return 0; + } +#else + /* From libpng-1.5.6 the overwrite should be fixed, so compare the trailing + * bits too: + */ + if (memcmp(pa, pb, (bit_width+7)>>3) == 0) + return 0; +#endif + + /* Return the index of the changed byte. */ + { + png_uint_32 where = 0; + + while (pa[where] == pb[where]) ++where; + return 1+where; + } +} +#endif /* PNG_READ_SUPPORTED */ + +/*************************** BASIC PNG FILE WRITING ***************************/ +/* A png_store takes data from the sequential writer or provides data + * to the sequential reader. It can also store the result of a PNG + * write for later retrieval. + */ +#define STORE_BUFFER_SIZE 500 /* arbitrary */ +typedef struct png_store_buffer +{ + struct png_store_buffer* prev; /* NOTE: stored in reverse order */ + png_byte buffer[STORE_BUFFER_SIZE]; +} png_store_buffer; + +#define FILE_NAME_SIZE 64 + +typedef struct store_palette_entry /* record of a single palette entry */ +{ + png_byte red; + png_byte green; + png_byte blue; + png_byte alpha; +} store_palette_entry, store_palette[256]; + +typedef struct png_store_file +{ + struct png_store_file* next; /* as many as you like... */ + char name[FILE_NAME_SIZE]; + png_uint_32 id; /* must be correct (see FILEID) */ + png_size_t datacount; /* In this (the last) buffer */ + png_store_buffer data; /* Last buffer in file */ + int npalette; /* Number of entries in palette */ + store_palette_entry* palette; /* May be NULL */ +} png_store_file; + +/* The following is a pool of memory allocated by a single libpng read or write + * operation. + */ +typedef struct store_pool +{ + struct png_store *store; /* Back pointer */ + struct store_memory *list; /* List of allocated memory */ + png_byte mark[4]; /* Before and after data */ + + /* Statistics for this run. */ + png_alloc_size_t max; /* Maximum single allocation */ + png_alloc_size_t current; /* Current allocation */ + png_alloc_size_t limit; /* Highest current allocation */ + png_alloc_size_t total; /* Total allocation */ + + /* Overall statistics (retained across successive runs). */ + png_alloc_size_t max_max; + png_alloc_size_t max_limit; + png_alloc_size_t max_total; +} store_pool; + +typedef struct png_store +{ + /* For cexcept.h exception handling - simply store one of these; + * the context is a self pointer but it may point to a different + * png_store (in fact it never does in this program.) + */ + struct exception_context + exception_context; + + unsigned int verbose :1; + unsigned int treat_warnings_as_errors :1; + unsigned int expect_error :1; + unsigned int expect_warning :1; + unsigned int saw_warning :1; + unsigned int speed :1; + unsigned int progressive :1; /* use progressive read */ + unsigned int validated :1; /* used as a temporary flag */ + int nerrors; + int nwarnings; + char test[128]; /* Name of test */ + char error[256]; + + /* Read fields */ + png_structp pread; /* Used to read a saved file */ + png_infop piread; + png_store_file* current; /* Set when reading */ + png_store_buffer* next; /* Set when reading */ + png_size_t readpos; /* Position in *next */ + png_byte* image; /* Buffer for reading interlaced images */ + png_size_t cb_image; /* Size of this buffer */ + png_size_t cb_row; /* Row size of the image(s) */ + png_uint_32 image_h; /* Number of rows in a single image */ + store_pool read_memory_pool; + + /* Write fields */ + png_store_file* saved; + png_structp pwrite; /* Used when writing a new file */ + png_infop piwrite; + png_size_t writepos; /* Position in .new */ + char wname[FILE_NAME_SIZE]; + png_store_buffer new; /* The end of the new PNG file being written. */ + store_pool write_memory_pool; + store_palette_entry* palette; + int npalette; +} png_store; + +/* Initialization and cleanup */ +static void +store_pool_mark(png_bytep mark) +{ + static png_uint_32 store_seed[2] = { 0x12345678, 1}; + + make_four_random_bytes(store_seed, mark); +} + +#ifdef PNG_READ_SUPPORTED +/* Use this for random 32 bit values; this function makes sure the result is + * non-zero. + */ +static png_uint_32 +random_32(void) +{ + + for(;;) + { + png_byte mark[4]; + png_uint_32 result; + + store_pool_mark(mark); + result = png_get_uint_32(mark); + + if (result != 0) + return result; + } +} +#endif /* PNG_READ_SUPPORTED */ + +static void +store_pool_init(png_store *ps, store_pool *pool) +{ + memset(pool, 0, sizeof *pool); + + pool->store = ps; + pool->list = NULL; + pool->max = pool->current = pool->limit = pool->total = 0; + pool->max_max = pool->max_limit = pool->max_total = 0; + store_pool_mark(pool->mark); +} + +static void +store_init(png_store* ps) +{ + memset(ps, 0, sizeof *ps); + init_exception_context(&ps->exception_context); + store_pool_init(ps, &ps->read_memory_pool); + store_pool_init(ps, &ps->write_memory_pool); + ps->verbose = 0; + ps->treat_warnings_as_errors = 0; + ps->expect_error = 0; + ps->expect_warning = 0; + ps->saw_warning = 0; + ps->speed = 0; + ps->progressive = 0; + ps->validated = 0; + ps->nerrors = ps->nwarnings = 0; + ps->pread = NULL; + ps->piread = NULL; + ps->saved = ps->current = NULL; + ps->next = NULL; + ps->readpos = 0; + ps->image = NULL; + ps->cb_image = 0; + ps->cb_row = 0; + ps->image_h = 0; + ps->pwrite = NULL; + ps->piwrite = NULL; + ps->writepos = 0; + ps->new.prev = NULL; + ps->palette = NULL; + ps->npalette = 0; +} + +static void +store_freebuffer(png_store_buffer* psb) +{ + if (psb->prev) + { + store_freebuffer(psb->prev); + free(psb->prev); + psb->prev = NULL; + } +} + +static void +store_freenew(png_store *ps) +{ + store_freebuffer(&ps->new); + ps->writepos = 0; + if (ps->palette != NULL) + { + free(ps->palette); + ps->palette = NULL; + ps->npalette = 0; + } +} + +static void +store_storenew(png_store *ps) +{ + png_store_buffer *pb; + + if (ps->writepos != STORE_BUFFER_SIZE) + png_error(ps->pwrite, "invalid store call"); + + pb = voidcast(png_store_buffer*, malloc(sizeof *pb)); + + if (pb == NULL) + png_error(ps->pwrite, "store new: OOM"); + + *pb = ps->new; + ps->new.prev = pb; + ps->writepos = 0; +} + +static void +store_freefile(png_store_file **ppf) +{ + if (*ppf != NULL) + { + store_freefile(&(*ppf)->next); + + store_freebuffer(&(*ppf)->data); + (*ppf)->datacount = 0; + if ((*ppf)->palette != NULL) + { + free((*ppf)->palette); + (*ppf)->palette = NULL; + (*ppf)->npalette = 0; + } + free(*ppf); + *ppf = NULL; + } +} + +/* Main interface to file storeage, after writing a new PNG file (see the API + * below) call store_storefile to store the result with the given name and id. + */ +static void +store_storefile(png_store *ps, png_uint_32 id) +{ + png_store_file *pf = voidcast(png_store_file*, malloc(sizeof *pf)); + if (pf == NULL) + png_error(ps->pwrite, "storefile: OOM"); + safecat(pf->name, sizeof pf->name, 0, ps->wname); + pf->id = id; + pf->data = ps->new; + pf->datacount = ps->writepos; + ps->new.prev = NULL; + ps->writepos = 0; + pf->palette = ps->palette; + pf->npalette = ps->npalette; + ps->palette = 0; + ps->npalette = 0; + + /* And save it. */ + pf->next = ps->saved; + ps->saved = pf; +} + +/* Generate an error message (in the given buffer) */ +static size_t +store_message(png_store *ps, png_const_structp pp, char *buffer, size_t bufsize, + size_t pos, PNG_CONST char *msg) +{ + if (pp != NULL && pp == ps->pread) + { + /* Reading a file */ + pos = safecat(buffer, bufsize, pos, "read: "); + + if (ps->current != NULL) + { + pos = safecat(buffer, bufsize, pos, ps->current->name); + pos = safecat(buffer, bufsize, pos, sep); + } + } + + else if (pp != NULL && pp == ps->pwrite) + { + /* Writing a file */ + pos = safecat(buffer, bufsize, pos, "write: "); + pos = safecat(buffer, bufsize, pos, ps->wname); + pos = safecat(buffer, bufsize, pos, sep); + } + + else + { + /* Neither reading nor writing (or a memory error in struct delete) */ + pos = safecat(buffer, bufsize, pos, "pngvalid: "); + } + + if (ps->test[0] != 0) + { + pos = safecat(buffer, bufsize, pos, ps->test); + pos = safecat(buffer, bufsize, pos, sep); + } + pos = safecat(buffer, bufsize, pos, msg); + return pos; +} + +/* Verbose output to the error stream: */ +static void +store_verbose(png_store *ps, png_const_structp pp, png_const_charp prefix, + png_const_charp message) +{ + char buffer[512]; + + if (prefix) + fputs(prefix, stderr); + + (void)store_message(ps, pp, buffer, sizeof buffer, 0, message); + fputs(buffer, stderr); + fputc('\n', stderr); +} + +/* Log an error or warning - the relevant count is always incremented. */ +static void +store_log(png_store* ps, png_const_structp pp, png_const_charp message, + int is_error) +{ + /* The warning is copied to the error buffer if there are no errors and it is + * the first warning. The error is copied to the error buffer if it is the + * first error (overwriting any prior warnings). + */ + if (is_error ? (ps->nerrors)++ == 0 : + (ps->nwarnings)++ == 0 && ps->nerrors == 0) + store_message(ps, pp, ps->error, sizeof ps->error, 0, message); + + if (ps->verbose) + store_verbose(ps, pp, is_error ? "error: " : "warning: ", message); +} + +#ifdef PNG_READ_SUPPORTED +/* Internal error function, called with a png_store but no libpng stuff. */ +static void +internal_error(png_store *ps, png_const_charp message) +{ + store_log(ps, NULL, message, 1 /* error */); + + /* And finally throw an exception. */ + { + struct exception_context *the_exception_context = &ps->exception_context; + Throw ps; + } +} +#endif /* PNG_READ_SUPPORTED */ + +/* Functions to use as PNG callbacks. */ +static void +store_error(png_structp ppIn, png_const_charp message) /* PNG_NORETURN */ +{ + png_const_structp pp = ppIn; + png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); + + if (!ps->expect_error) + store_log(ps, pp, message, 1 /* error */); + + /* And finally throw an exception. */ + { + struct exception_context *the_exception_context = &ps->exception_context; + Throw ps; + } +} + +static void +store_warning(png_structp ppIn, png_const_charp message) +{ + png_const_structp pp = ppIn; + png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); + + if (!ps->expect_warning) + store_log(ps, pp, message, 0 /* warning */); + else + ps->saw_warning = 1; +} + +/* These somewhat odd functions are used when reading an image to ensure that + * the buffer is big enough, the png_structp is for errors. + */ +/* Return a single row from the correct image. */ +static png_bytep +store_image_row(PNG_CONST png_store* ps, png_const_structp pp, int nImage, + png_uint_32 y) +{ + png_size_t coffset = (nImage * ps->image_h + y) * (ps->cb_row + 5) + 2; + + if (ps->image == NULL) + png_error(pp, "no allocated image"); + + if (coffset + ps->cb_row + 3 > ps->cb_image) + png_error(pp, "image too small"); + + return ps->image + coffset; +} + +static void +store_image_free(png_store *ps, png_const_structp pp) +{ + if (ps->image != NULL) + { + png_bytep image = ps->image; + + if (image[-1] != 0xed || image[ps->cb_image] != 0xfe) + { + if (pp != NULL) + png_error(pp, "png_store image overwrite (1)"); + else + store_log(ps, NULL, "png_store image overwrite (2)", 1); + } + + ps->image = NULL; + ps->cb_image = 0; + --image; + free(image); + } +} + +static void +store_ensure_image(png_store *ps, png_const_structp pp, int nImages, + png_size_t cbRow, png_uint_32 cRows) +{ + png_size_t cb = nImages * cRows * (cbRow + 5); + + if (ps->cb_image < cb) + { + png_bytep image; + + store_image_free(ps, pp); + + /* The buffer is deliberately mis-aligned. */ + image = voidcast(png_bytep, malloc(cb+2)); + if (image == NULL) + { + /* Called from the startup - ignore the error for the moment. */ + if (pp == NULL) + return; + + png_error(pp, "OOM allocating image buffer"); + } + + /* These magic tags are used to detect overwrites above. */ + ++image; + image[-1] = 0xed; + image[cb] = 0xfe; + + ps->image = image; + ps->cb_image = cb; + } + + /* We have an adequate sized image; lay out the rows. There are 2 bytes at + * the start and three at the end of each (this ensures that the row + * alignment starts out odd - 2+1 and changes for larger images on each row.) + */ + ps->cb_row = cbRow; + ps->image_h = cRows; + + /* For error checking, the whole buffer is set to 10110010 (0xb2 - 178). + * This deliberately doesn't match the bits in the size test image which are + * outside the image; these are set to 0xff (all 1). To make the row + * comparison work in the 'size' test case the size rows are pre-initialized + * to the same value prior to calling 'standard_row'. + */ + memset(ps->image, 178, cb); + + /* Then put in the marks. */ + while (--nImages >= 0) + { + png_uint_32 y; + + for (y=0; yimage; + + if (image[-1] != 0xed || image[ps->cb_image] != 0xfe) + png_error(pp, "image overwrite"); + else + { + png_size_t cbRow = ps->cb_row; + png_uint_32 rows = ps->image_h; + + image += iImage * (cbRow+5) * ps->image_h; + + image += 2; /* skip image first row markers */ + + while (rows-- > 0) + { + if (image[-2] != 190 || image[-1] != 239) + png_error(pp, "row start overwritten"); + + if (image[cbRow] != 222 || image[cbRow+1] != 173 || + image[cbRow+2] != 17) + png_error(pp, "row end overwritten"); + + image += cbRow+5; + } + } +} +#endif /* PNG_READ_SUPPORTED */ + +static void +store_write(png_structp ppIn, png_bytep pb, png_size_t st) +{ + png_const_structp pp = ppIn; + png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); + + if (ps->pwrite != pp) + png_error(pp, "store state damaged"); + + while (st > 0) + { + size_t cb; + + if (ps->writepos >= STORE_BUFFER_SIZE) + store_storenew(ps); + + cb = st; + + if (cb > STORE_BUFFER_SIZE - ps->writepos) + cb = STORE_BUFFER_SIZE - ps->writepos; + + memcpy(ps->new.buffer + ps->writepos, pb, cb); + pb += cb; + st -= cb; + ps->writepos += cb; + } +} + +static void +store_flush(png_structp ppIn) +{ + UNUSED(ppIn) /*DOES NOTHING*/ +} + +#ifdef PNG_READ_SUPPORTED +static size_t +store_read_buffer_size(png_store *ps) +{ + /* Return the bytes available for read in the current buffer. */ + if (ps->next != &ps->current->data) + return STORE_BUFFER_SIZE; + + return ps->current->datacount; +} + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Return total bytes available for read. */ +static size_t +store_read_buffer_avail(png_store *ps) +{ + if (ps->current != NULL && ps->next != NULL) + { + png_store_buffer *next = &ps->current->data; + size_t cbAvail = ps->current->datacount; + + while (next != ps->next && next != NULL) + { + next = next->prev; + cbAvail += STORE_BUFFER_SIZE; + } + + if (next != ps->next) + png_error(ps->pread, "buffer read error"); + + if (cbAvail > ps->readpos) + return cbAvail - ps->readpos; + } + + return 0; +} +#endif + +static int +store_read_buffer_next(png_store *ps) +{ + png_store_buffer *pbOld = ps->next; + png_store_buffer *pbNew = &ps->current->data; + if (pbOld != pbNew) + { + while (pbNew != NULL && pbNew->prev != pbOld) + pbNew = pbNew->prev; + + if (pbNew != NULL) + { + ps->next = pbNew; + ps->readpos = 0; + return 1; + } + + png_error(ps->pread, "buffer lost"); + } + + return 0; /* EOF or error */ +} + +/* Need separate implementation and callback to allow use of the same code + * during progressive read, where the io_ptr is set internally by libpng. + */ +static void +store_read_imp(png_store *ps, png_bytep pb, png_size_t st) +{ + if (ps->current == NULL || ps->next == NULL) + png_error(ps->pread, "store state damaged"); + + while (st > 0) + { + size_t cbAvail = store_read_buffer_size(ps) - ps->readpos; + + if (cbAvail > 0) + { + if (cbAvail > st) cbAvail = st; + memcpy(pb, ps->next->buffer + ps->readpos, cbAvail); + st -= cbAvail; + pb += cbAvail; + ps->readpos += cbAvail; + } + + else if (!store_read_buffer_next(ps)) + png_error(ps->pread, "read beyond end of file"); + } +} + +static void +store_read(png_structp ppIn, png_bytep pb, png_size_t st) +{ + png_const_structp pp = ppIn; + png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); + + if (ps == NULL || ps->pread != pp) + png_error(pp, "bad store read call"); + + store_read_imp(ps, pb, st); +} + +static void +store_progressive_read(png_store *ps, png_structp pp, png_infop pi) +{ + /* Notice that a call to store_read will cause this function to fail because + * readpos will be set. + */ + if (ps->pread != pp || ps->current == NULL || ps->next == NULL) + png_error(pp, "store state damaged (progressive)"); + + do + { + if (ps->readpos != 0) + png_error(pp, "store_read called during progressive read"); + + png_process_data(pp, pi, ps->next->buffer, store_read_buffer_size(ps)); + } + while (store_read_buffer_next(ps)); +} +#endif /* PNG_READ_SUPPORTED */ + +/* The caller must fill this in: */ +static store_palette_entry * +store_write_palette(png_store *ps, int npalette) +{ + if (ps->pwrite == NULL) + store_log(ps, NULL, "attempt to write palette without write stream", 1); + + if (ps->palette != NULL) + png_error(ps->pwrite, "multiple store_write_palette calls"); + + /* This function can only return NULL if called with '0'! */ + if (npalette > 0) + { + ps->palette = voidcast(store_palette_entry*, malloc(npalette * + sizeof *ps->palette)); + + if (ps->palette == NULL) + png_error(ps->pwrite, "store new palette: OOM"); + + ps->npalette = npalette; + } + + return ps->palette; +} + +#ifdef PNG_READ_SUPPORTED +static store_palette_entry * +store_current_palette(png_store *ps, int *npalette) +{ + /* This is an internal error (the call has been made outside a read + * operation.) + */ + if (ps->current == NULL) + store_log(ps, ps->pread, "no current stream for palette", 1); + + /* The result may be null if there is no palette. */ + *npalette = ps->current->npalette; + return ps->current->palette; +} +#endif /* PNG_READ_SUPPORTED */ + +/***************************** MEMORY MANAGEMENT*** ***************************/ +/* A store_memory is simply the header for an allocated block of memory. The + * pointer returned to libpng is just after the end of the header block, the + * allocated memory is followed by a second copy of the 'mark'. + */ +typedef struct store_memory +{ + store_pool *pool; /* Originating pool */ + struct store_memory *next; /* Singly linked list */ + png_alloc_size_t size; /* Size of memory allocated */ + png_byte mark[4]; /* ID marker */ +} store_memory; + +/* Handle a fatal error in memory allocation. This calls png_error if the + * libpng struct is non-NULL, else it outputs a message and returns. This means + * that a memory problem while libpng is running will abort (png_error) the + * handling of particular file while one in cleanup (after the destroy of the + * struct has returned) will simply keep going and free (or attempt to free) + * all the memory. + */ +static void +store_pool_error(png_store *ps, png_const_structp pp, PNG_CONST char *msg) +{ + if (pp != NULL) + png_error(pp, msg); + + /* Else we have to do it ourselves. png_error eventually calls store_log, + * above. store_log accepts a NULL png_structp - it just changes what gets + * output by store_message. + */ + store_log(ps, pp, msg, 1 /* error */); +} + +static void +store_memory_free(png_const_structp pp, store_pool *pool, store_memory *memory) +{ + /* Note that pp may be NULL (see store_pool_delete below), the caller has + * found 'memory' in pool->list *and* unlinked this entry, so this is a valid + * pointer (for sure), but the contents may have been trashed. + */ + if (memory->pool != pool) + store_pool_error(pool->store, pp, "memory corrupted (pool)"); + + else if (memcmp(memory->mark, pool->mark, sizeof memory->mark) != 0) + store_pool_error(pool->store, pp, "memory corrupted (start)"); + + /* It should be safe to read the size field now. */ + else + { + png_alloc_size_t cb = memory->size; + + if (cb > pool->max) + store_pool_error(pool->store, pp, "memory corrupted (size)"); + + else if (memcmp((png_bytep)(memory+1)+cb, pool->mark, sizeof pool->mark) + != 0) + store_pool_error(pool->store, pp, "memory corrupted (end)"); + + /* Finally give the library a chance to find problems too: */ + else + { + pool->current -= cb; + free(memory); + } + } +} + +static void +store_pool_delete(png_store *ps, store_pool *pool) +{ + if (pool->list != NULL) + { + fprintf(stderr, "%s: %s %s: memory lost (list follows):\n", ps->test, + pool == &ps->read_memory_pool ? "read" : "write", + pool == &ps->read_memory_pool ? (ps->current != NULL ? + ps->current->name : "unknown file") : ps->wname); + ++ps->nerrors; + + do + { + store_memory *next = pool->list; + pool->list = next->next; + next->next = NULL; + + fprintf(stderr, "\t%lu bytes @ %p\n", + (unsigned long)next->size, (PNG_CONST void*)(next+1)); + /* The NULL means this will always return, even if the memory is + * corrupted. + */ + store_memory_free(NULL, pool, next); + } + while (pool->list != NULL); + } + + /* And reset the other fields too for the next time. */ + if (pool->max > pool->max_max) pool->max_max = pool->max; + pool->max = 0; + if (pool->current != 0) /* unexpected internal error */ + fprintf(stderr, "%s: %s %s: memory counter mismatch (internal error)\n", + ps->test, pool == &ps->read_memory_pool ? "read" : "write", + pool == &ps->read_memory_pool ? (ps->current != NULL ? + ps->current->name : "unknown file") : ps->wname); + pool->current = 0; + + if (pool->limit > pool->max_limit) + pool->max_limit = pool->limit; + + pool->limit = 0; + + if (pool->total > pool->max_total) + pool->max_total = pool->total; + + pool->total = 0; + + /* Get a new mark too. */ + store_pool_mark(pool->mark); +} + +/* The memory callbacks: */ +static png_voidp +store_malloc(png_structp ppIn, png_alloc_size_t cb) +{ + png_const_structp pp = ppIn; + store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp)); + store_memory *new = voidcast(store_memory*, malloc(cb + (sizeof *new) + + (sizeof pool->mark))); + + if (new != NULL) + { + if (cb > pool->max) + pool->max = cb; + + pool->current += cb; + + if (pool->current > pool->limit) + pool->limit = pool->current; + + pool->total += cb; + + new->size = cb; + memcpy(new->mark, pool->mark, sizeof new->mark); + memcpy((png_byte*)(new+1) + cb, pool->mark, sizeof pool->mark); + new->pool = pool; + new->next = pool->list; + pool->list = new; + ++new; + } + + else + { + /* NOTE: the PNG user malloc function cannot use the png_ptr it is passed + * other than to retrieve the allocation pointer! libpng calls the + * store_malloc callback in two basic cases: + * + * 1) From png_malloc; png_malloc will do a png_error itself if NULL is + * returned. + * 2) From png_struct or png_info structure creation; png_malloc is + * to return so cleanup can be performed. + * + * To handle this store_malloc can log a message, but can't do anything + * else. + */ + store_log(pool->store, pp, "out of memory", 1 /* is_error */); + } + + return new; +} + +static void +store_free(png_structp ppIn, png_voidp memory) +{ + png_const_structp pp = ppIn; + store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp)); + store_memory *this = voidcast(store_memory*, memory), **test; + + /* Because libpng calls store_free with a dummy png_struct when deleting + * png_struct or png_info via png_destroy_struct_2 it is necessary to check + * the passed in png_structp to ensure it is valid, and not pass it to + * png_error if it is not. + */ + if (pp != pool->store->pread && pp != pool->store->pwrite) + pp = NULL; + + /* First check that this 'memory' really is valid memory - it must be in the + * pool list. If it is, use the shared memory_free function to free it. + */ + --this; + for (test = &pool->list; *test != this; test = &(*test)->next) + { + if (*test == NULL) + { + store_pool_error(pool->store, pp, "bad pointer to free"); + return; + } + } + + /* Unlink this entry, *test == this. */ + *test = this->next; + this->next = NULL; + store_memory_free(pp, pool, this); +} + +/* Setup functions. */ +/* Cleanup when aborting a write or after storing the new file. */ +static void +store_write_reset(png_store *ps) +{ + if (ps->pwrite != NULL) + { + anon_context(ps); + + Try + png_destroy_write_struct(&ps->pwrite, &ps->piwrite); + + Catch_anonymous + { + /* memory corruption: continue. */ + } + + ps->pwrite = NULL; + ps->piwrite = NULL; + } + + /* And make sure that all the memory has been freed - this will output + * spurious errors in the case of memory corruption above, but this is safe. + */ + store_pool_delete(ps, &ps->write_memory_pool); + + store_freenew(ps); +} + +/* The following is the main write function, it returns a png_struct and, + * optionally, a png_info suitable for writiing a new PNG file. Use + * store_storefile above to record this file after it has been written. The + * returned libpng structures as destroyed by store_write_reset above. + */ +static png_structp +set_store_for_write(png_store *ps, png_infopp ppi, + PNG_CONST char * volatile name) +{ + anon_context(ps); + + Try + { + if (ps->pwrite != NULL) + png_error(ps->pwrite, "write store already in use"); + + store_write_reset(ps); + safecat(ps->wname, sizeof ps->wname, 0, name); + + /* Don't do the slow memory checks if doing a speed test. */ + if (ps->speed) + ps->pwrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, + ps, store_error, store_warning); + + else + ps->pwrite = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, + ps, store_error, store_warning, &ps->write_memory_pool, + store_malloc, store_free); + + png_set_write_fn(ps->pwrite, ps, store_write, store_flush); + + if (ppi != NULL) + *ppi = ps->piwrite = png_create_info_struct(ps->pwrite); + } + + Catch_anonymous + return NULL; + + return ps->pwrite; +} + +/* Cleanup when finished reading (either due to error or in the success case). + * This routine exists even when there is no read support to make the code + * tidier (avoid a mass of ifdefs) and so easier to maintain. + */ +static void +store_read_reset(png_store *ps) +{ +# ifdef PNG_READ_SUPPORTED + if (ps->pread != NULL) + { + anon_context(ps); + + Try + png_destroy_read_struct(&ps->pread, &ps->piread, NULL); + + Catch_anonymous + { + /* error already output: continue */ + } + + ps->pread = NULL; + ps->piread = NULL; + } +# endif + + /* Always do this to be safe. */ + store_pool_delete(ps, &ps->read_memory_pool); + + ps->current = NULL; + ps->next = NULL; + ps->readpos = 0; + ps->validated = 0; +} + +#ifdef PNG_READ_SUPPORTED +static void +store_read_set(png_store *ps, png_uint_32 id) +{ + png_store_file *pf = ps->saved; + + while (pf != NULL) + { + if (pf->id == id) + { + ps->current = pf; + ps->next = NULL; + store_read_buffer_next(ps); + return; + } + + pf = pf->next; + } + + { + size_t pos; + char msg[FILE_NAME_SIZE+64]; + + pos = standard_name_from_id(msg, sizeof msg, 0, id); + pos = safecat(msg, sizeof msg, pos, ": file not found"); + png_error(ps->pread, msg); + } +} + +/* The main interface for reading a saved file - pass the id number of the file + * to retrieve. Ids must be unique or the earlier file will be hidden. The API + * returns a png_struct and, optionally, a png_info. Both of these will be + * destroyed by store_read_reset above. + */ +static png_structp +set_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id, + PNG_CONST char *name) +{ + /* Set the name for png_error */ + safecat(ps->test, sizeof ps->test, 0, name); + + if (ps->pread != NULL) + png_error(ps->pread, "read store already in use"); + + store_read_reset(ps); + + /* Both the create APIs can return NULL if used in their default mode + * (because there is no other way of handling an error because the jmp_buf + * by default is stored in png_struct and that has not been allocated!) + * However, given that store_error works correctly in these circumstances + * we don't ever expect NULL in this program. + */ + if (ps->speed) + ps->pread = png_create_read_struct(PNG_LIBPNG_VER_STRING, ps, + store_error, store_warning); + + else + ps->pread = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, ps, + store_error, store_warning, &ps->read_memory_pool, store_malloc, + store_free); + + if (ps->pread == NULL) + { + struct exception_context *the_exception_context = &ps->exception_context; + + store_log(ps, NULL, "png_create_read_struct returned NULL (unexpected)", + 1 /*error*/); + + Throw ps; + } + + store_read_set(ps, id); + + if (ppi != NULL) + *ppi = ps->piread = png_create_info_struct(ps->pread); + + return ps->pread; +} +#endif /* PNG_READ_SUPPORTED */ + +/* The overall cleanup of a store simply calls the above then removes all the + * saved files. This does not delete the store itself. + */ +static void +store_delete(png_store *ps) +{ + store_write_reset(ps); + store_read_reset(ps); + store_freefile(&ps->saved); + store_image_free(ps, NULL); +} + +/*********************** PNG FILE MODIFICATION ON READ ************************/ +/* Files may be modified on read. The following structure contains a complete + * png_store together with extra members to handle modification and a special + * read callback for libpng. To use this the 'modifications' field must be set + * to a list of png_modification structures that actually perform the + * modification, otherwise a png_modifier is functionally equivalent to a + * png_store. There is a special read function, set_modifier_for_read, which + * replaces set_store_for_read. + */ +typedef enum modifier_state +{ + modifier_start, /* Initial value */ + modifier_signature, /* Have a signature */ + modifier_IHDR /* Have an IHDR */ +} modifier_state; + +typedef struct CIE_color +{ + /* A single CIE tristimulus value, representing the unique response of a + * standard observer to a variety of light spectra. The observer recognizes + * all spectra that produce this response as the same color, therefore this + * is effectively a description of a color. + */ + double X, Y, Z; +} CIE_color; + +typedef struct color_encoding +{ + /* A description of an (R,G,B) encoding of color (as defined above); this + * includes the actual colors of the (R,G,B) triples (1,0,0), (0,1,0) and + * (0,0,1) plus an encoding value that is used to encode the linear + * components R, G and B to give the actual values R^gamma, G^gamma and + * B^gamma that are stored. + */ + double gamma; /* Encoding (file) gamma of space */ + CIE_color red, green, blue; /* End points */ +} color_encoding; + +#ifdef PNG_READ_SUPPORTED +static double +chromaticity_x(CIE_color c) +{ + return c.X / (c.X + c.Y + c.Z); +} + +static double +chromaticity_y(CIE_color c) +{ + return c.Y / (c.X + c.Y + c.Z); +} + +static CIE_color +white_point(PNG_CONST color_encoding *encoding) +{ + CIE_color white; + + white.X = encoding->red.X + encoding->green.X + encoding->blue.X; + white.Y = encoding->red.Y + encoding->green.Y + encoding->blue.Y; + white.Z = encoding->red.Z + encoding->green.Z + encoding->blue.Z; + + return white; +} + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +static void +normalize_color_encoding(color_encoding *encoding) +{ + PNG_CONST double whiteY = encoding->red.Y + encoding->green.Y + + encoding->blue.Y; + + if (whiteY != 1) + { + encoding->red.X /= whiteY; + encoding->red.Y /= whiteY; + encoding->red.Z /= whiteY; + encoding->green.X /= whiteY; + encoding->green.Y /= whiteY; + encoding->green.Z /= whiteY; + encoding->blue.X /= whiteY; + encoding->blue.Y /= whiteY; + encoding->blue.Z /= whiteY; + } +} +#endif + +static size_t +safecat_color_encoding(char *buffer, size_t bufsize, size_t pos, + PNG_CONST color_encoding *e, double encoding_gamma) +{ + if (e != 0) + { + if (encoding_gamma != 0) + pos = safecat(buffer, bufsize, pos, "("); + pos = safecat(buffer, bufsize, pos, "R("); + pos = safecatd(buffer, bufsize, pos, e->red.X, 4); + pos = safecat(buffer, bufsize, pos, ","); + pos = safecatd(buffer, bufsize, pos, e->red.Y, 4); + pos = safecat(buffer, bufsize, pos, ","); + pos = safecatd(buffer, bufsize, pos, e->red.Z, 4); + pos = safecat(buffer, bufsize, pos, "),G("); + pos = safecatd(buffer, bufsize, pos, e->green.X, 4); + pos = safecat(buffer, bufsize, pos, ","); + pos = safecatd(buffer, bufsize, pos, e->green.Y, 4); + pos = safecat(buffer, bufsize, pos, ","); + pos = safecatd(buffer, bufsize, pos, e->green.Z, 4); + pos = safecat(buffer, bufsize, pos, "),B("); + pos = safecatd(buffer, bufsize, pos, e->blue.X, 4); + pos = safecat(buffer, bufsize, pos, ","); + pos = safecatd(buffer, bufsize, pos, e->blue.Y, 4); + pos = safecat(buffer, bufsize, pos, ","); + pos = safecatd(buffer, bufsize, pos, e->blue.Z, 4); + pos = safecat(buffer, bufsize, pos, ")"); + if (encoding_gamma != 0) + pos = safecat(buffer, bufsize, pos, ")"); + } + + if (encoding_gamma != 0) + { + pos = safecat(buffer, bufsize, pos, "^"); + pos = safecatd(buffer, bufsize, pos, encoding_gamma, 5); + } + + return pos; +} +#endif /* PNG_READ_SUPPORTED */ + +typedef struct png_modifier +{ + png_store this; /* I am a png_store */ + struct png_modification *modifications; /* Changes to make */ + + modifier_state state; /* My state */ + + /* Information from IHDR: */ + png_byte bit_depth; /* From IHDR */ + png_byte colour_type; /* From IHDR */ + + /* While handling PLTE, IDAT and IEND these chunks may be pended to allow + * other chunks to be inserted. + */ + png_uint_32 pending_len; + png_uint_32 pending_chunk; + + /* Test values */ + double *gammas; + unsigned int ngammas; + unsigned int ngamma_tests; /* Number of gamma tests to run*/ + double current_gamma; /* 0 if not set */ + PNG_CONST color_encoding *encodings; + unsigned int nencodings; + PNG_CONST color_encoding *current_encoding; /* If an encoding has been set */ + unsigned int encoding_counter; /* For iteration */ + int encoding_ignored; /* Something overwrote it */ + + /* Control variables used to iterate through possible encodings, the + * following must be set to 0 and tested by the function that uses the + * png_modifier because the modifier only sets it to 1 (true.) + */ + unsigned int repeat :1; /* Repeat this transform test. */ + unsigned int test_uses_encoding :1; + + /* Lowest sbit to test (libpng fails for sbit < 8) */ + png_byte sbitlow; + + /* Error control - these are the limits on errors accepted by the gamma tests + * below. + */ + double maxout8; /* Maximum output value error */ + double maxabs8; /* Absolute sample error 0..1 */ + double maxcalc8; /* Absolute sample error 0..1 */ + double maxpc8; /* Percentage sample error 0..100% */ + double maxout16; /* Maximum output value error */ + double maxabs16; /* Absolute sample error 0..1 */ + double maxcalc16;/* Absolute sample error 0..1 */ + double maxpc16; /* Percentage sample error 0..100% */ + + /* This is set by transforms that need to allow a higher limit, it is an + * internal check on pngvalid to ensure that the calculated error limits are + * not ridiculous; without this it is too easy to make a mistake in pngvalid + * that allows any value through. + */ + double limit; /* limit on error values, normally 4E-3 */ + + /* Log limits - values above this are logged, but not necessarily + * warned. + */ + double log8; /* Absolute error in 8 bits to log */ + double log16; /* Absolute error in 16 bits to log */ + + /* Logged 8 and 16 bit errors ('output' values): */ + double error_gray_2; + double error_gray_4; + double error_gray_8; + double error_gray_16; + double error_color_8; + double error_color_16; + double error_indexed; + + /* Flags: */ + /* Whether to call png_read_update_info, not png_read_start_image, and how + * many times to call it. + */ + int use_update_info; + + /* Whether or not to interlace. */ + int interlace_type :9; /* int, but must store '1' */ + + /* Run the standard tests? */ + unsigned int test_standard :1; + + /* Run the odd-sized image and interlace read/write tests? */ + unsigned int test_size :1; + + /* Run tests on reading with a combiniation of transforms, */ + unsigned int test_transform :1; + + /* When to use the use_input_precision option: */ + unsigned int use_input_precision :1; + unsigned int use_input_precision_sbit :1; + unsigned int use_input_precision_16to8 :1; + + /* If set assume that the calculation bit depth is set by the input + * precision, not the output precision. + */ + unsigned int calculations_use_input_precision :1; + + /* If set assume that the calculations are done in 16 bits even if both input + * and output are 8 bit or less. + */ + unsigned int assume_16_bit_calculations :1; + + /* Which gamma tests to run: */ + unsigned int test_gamma_threshold :1; + unsigned int test_gamma_transform :1; /* main tests */ + unsigned int test_gamma_sbit :1; + unsigned int test_gamma_scale16 :1; + unsigned int test_gamma_background :1; + unsigned int test_gamma_alpha_mode :1; + unsigned int test_gamma_expand16 :1; + unsigned int test_exhaustive :1; + + unsigned int log :1; /* Log max error */ + + /* Buffer information, the buffer size limits the size of the chunks that can + * be modified - they must fit (including header and CRC) into the buffer! + */ + size_t flush; /* Count of bytes to flush */ + size_t buffer_count; /* Bytes in buffer */ + size_t buffer_position; /* Position in buffer */ + png_byte buffer[1024]; +} png_modifier; + +/* This returns true if the test should be stopped now because it has already + * failed and it is running silently. + */ +static int fail(png_modifier *pm) +{ + return !pm->log && !pm->this.verbose && (pm->this.nerrors > 0 || + (pm->this.treat_warnings_as_errors && pm->this.nwarnings > 0)); +} + +static void +modifier_init(png_modifier *pm) +{ + memset(pm, 0, sizeof *pm); + store_init(&pm->this); + pm->modifications = NULL; + pm->state = modifier_start; + pm->sbitlow = 1U; + pm->ngammas = 0; + pm->ngamma_tests = 0; + pm->gammas = 0; + pm->current_gamma = 0; + pm->encodings = 0; + pm->nencodings = 0; + pm->current_encoding = 0; + pm->encoding_counter = 0; + pm->encoding_ignored = 0; + pm->repeat = 0; + pm->test_uses_encoding = 0; + pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0; + pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0; + pm->limit = 4E-3; + pm->log8 = pm->log16 = 0; /* Means 'off' */ + pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0; + pm->error_gray_16 = pm->error_color_8 = pm->error_color_16 = 0; + pm->error_indexed = 0; + pm->use_update_info = 0; + pm->interlace_type = PNG_INTERLACE_NONE; + pm->test_standard = 0; + pm->test_size = 0; + pm->test_transform = 0; + pm->use_input_precision = 0; + pm->use_input_precision_sbit = 0; + pm->use_input_precision_16to8 = 0; + pm->calculations_use_input_precision = 0; + pm->test_gamma_threshold = 0; + pm->test_gamma_transform = 0; + pm->test_gamma_sbit = 0; + pm->test_gamma_scale16 = 0; + pm->test_gamma_background = 0; + pm->test_gamma_alpha_mode = 0; + pm->test_gamma_expand16 = 0; + pm->test_exhaustive = 0; + pm->log = 0; + + /* Rely on the memset for all the other fields - there are no pointers */ +} + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* If pm->calculations_use_input_precision is set then operations will happen + * with only 8 bit precision unless both the input and output bit depth are 16. + * + * If pm->assume_16_bit_calculations is set then even 8 bit calculations use 16 + * bit precision. This only affects those of the following limits that pertain + * to a calculation - not a digitization operation - unless the following API is + * called directly. + */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +static double digitize(PNG_CONST png_modifier *pm, double value, + int sample_depth, int do_round) +{ + /* 'value' is in the range 0 to 1, the result is the same value rounded to a + * multiple of the digitization factor - 8 or 16 bits depending on both the + * sample depth and the 'assume' setting. Digitization is normally by + * rounding and 'do_round' should be 1, if it is 0 the digitized value will + * be truncated. + */ + PNG_CONST unsigned int digitization_factor = + (pm->assume_16_bit_calculations || sample_depth == 16) ? 65535 : 255; + + /* Limiting the range is done as a convenience to the caller - it's easier to + * do it once here than every time at the call site. + */ + if (value <= 0) + value = 0; + else if (value >= 1) + value = 1; + + value *= digitization_factor; + if (do_round) value += .5; + return floor(value)/digitization_factor; +} +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) +{ + /* Absolute error permitted in linear values - affected by the bit depth of + * the calculations. + */ + if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 || + !pm->calculations_use_input_precision))) + return pm->maxabs16; + else + return pm->maxabs8; +} +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) +{ + /* Error in the linear composition arithmetic - only relevant when + * composition actually happens (0 < alpha < 1). + */ + if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 || + !pm->calculations_use_input_precision))) + return pm->maxcalc16; + else + return pm->maxcalc8; +} + +static double pcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) +{ + /* Percentage error permitted in the linear values. Note that the specified + * value is a percentage but this routine returns a simple number. + */ + if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 || + !pm->calculations_use_input_precision))) + return pm->maxpc16 * .01; + else + return pm->maxpc8 * .01; +} + +/* Output error - the error in the encoded value. This is determined by the + * digitization of the output so can be +/-0.5 in the actual output value. In + * the expand_16 case with the current code in libpng the expand happens after + * all the calculations are done in 8 bit arithmetic, so even though the output + * depth is 16 the output error is determined by the 8 bit calculation. + * + * This limit is not determined by the bit depth of internal calculations. + * + * The specified parameter does *not* include the base .5 digitization error but + * it is added here. + */ +static double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) +{ + /* There is a serious error in the 2 and 4 bit grayscale transform because + * the gamma table value (8 bits) is simply shifted, not rounded, so the + * error in 4 bit grayscale gamma is up to the value below. This is a hack + * to allow pngvalid to succeed: + * + * TODO: fix this in libpng + */ + if (out_depth == 2) + return .73182-.5; + + if (out_depth == 4) + return .90644-.5; + + if (out_depth == 16 && (in_depth == 16 || + !pm->calculations_use_input_precision)) + return pm->maxout16; + + /* This is the case where the value was calculated at 8-bit precision then + * scaled to 16 bits. + */ + else if (out_depth == 16) + return pm->maxout8 * 257; + + else + return pm->maxout8; +} + +/* This does the same thing as the above however it returns the value to log, + * rather than raising a warning. This is useful for debugging to track down + * exactly what set of parameters cause high error values. + */ +static double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth) +{ + /* The command line parameters are either 8 bit (0..255) or 16 bit (0..65535) + * and so must be adjusted for low bit depth grayscale: + */ + if (out_depth <= 8) + { + if (pm->log8 == 0) /* switched off */ + return 256; + + if (out_depth < 8) + return pm->log8 / 255 * ((1<log8; + } + + if (out_depth == 16 && (in_depth == 16 || + !pm->calculations_use_input_precision)) + { + if (pm->log16 == 0) + return 65536; + + return pm->log16; + } + + /* This is the case where the value was calculated at 8-bit precision then + * scaled to 16 bits. + */ + if (pm->log8 == 0) + return 65536; + + return pm->log8 * 257; +} + +/* This complements the above by providing the appropriate quantization for the + * final value. Normally this would just be quantization to an integral value, + * but in the 8 bit calculation case it's actually quantization to a multiple of + * 257! + */ +static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth, + int out_depth) +{ + if (out_depth == 16 && in_depth != 16 + && pm->calculations_use_input_precision) + return 257; + else + return 1; +} +#endif /* PNG_READ_GAMMA_SUPPORTED */ + +/* One modification structure must be provided for each chunk to be modified (in + * fact more than one can be provided if multiple separate changes are desired + * for a single chunk.) Modifications include adding a new chunk when a + * suitable chunk does not exist. + * + * The caller of modify_fn will reset the CRC of the chunk and record 'modified' + * or 'added' as appropriate if the modify_fn returns 1 (true). If the + * modify_fn is NULL the chunk is simply removed. + */ +typedef struct png_modification +{ + struct png_modification *next; + png_uint_32 chunk; + + /* If the following is NULL all matching chunks will be removed: */ + int (*modify_fn)(struct png_modifier *pm, + struct png_modification *me, int add); + + /* If the following is set to PLTE, IDAT or IEND and the chunk has not been + * found and modified (and there is a modify_fn) the modify_fn will be called + * to add the chunk before the relevant chunk. + */ + png_uint_32 add; + unsigned int modified :1; /* Chunk was modified */ + unsigned int added :1; /* Chunk was added */ + unsigned int removed :1; /* Chunk was removed */ +} png_modification; + +static void +modification_reset(png_modification *pmm) +{ + if (pmm != NULL) + { + pmm->modified = 0; + pmm->added = 0; + pmm->removed = 0; + modification_reset(pmm->next); + } +} + +static void +modification_init(png_modification *pmm) +{ + memset(pmm, 0, sizeof *pmm); + pmm->next = NULL; + pmm->chunk = 0; + pmm->modify_fn = NULL; + pmm->add = 0; + modification_reset(pmm); +} + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +static void +modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce) +{ + if (pm->current_encoding != 0) + *ce = *pm->current_encoding; + + else + memset(ce, 0, sizeof *ce); + + ce->gamma = pm->current_gamma; +} +#endif + +static size_t +safecat_current_encoding(char *buffer, size_t bufsize, size_t pos, + PNG_CONST png_modifier *pm) +{ + pos = safecat_color_encoding(buffer, bufsize, pos, pm->current_encoding, + pm->current_gamma); + + if (pm->encoding_ignored) + pos = safecat(buffer, bufsize, pos, "[overridden]"); + + return pos; +} + +/* Iterate through the usefully testable color encodings. An encoding is one + * of: + * + * 1) Nothing (no color space, no gamma). + * 2) Just a gamma value from the gamma array (including 1.0) + * 3) A color space from the encodings array with the corresponding gamma. + * 4) The same, but with gamma 1.0 (only really useful with 16 bit calculations) + * + * The iterator selects these in turn, the randomizer selects one at random, + * which is used depends on the setting of the 'test_exhaustive' flag. Notice + * that this function changes the colour space encoding so it must only be + * called on completion of the previous test. This is what 'modifier_reset' + * does, below. + * + * After the function has been called the 'repeat' flag will still be set; the + * caller of modifier_reset must reset it at the start of each run of the test! + */ +static unsigned int +modifier_total_encodings(PNG_CONST png_modifier *pm) +{ + return 1 + /* (1) nothing */ + pm->ngammas + /* (2) gamma values to test */ + pm->nencodings + /* (3) total number of encodings */ + /* The following test only works after the first time through the + * png_modifier code because 'bit_depth' is set when the IHDR is read. + * modifier_reset, below, preserves the setting until after it has called + * the iterate function (also below.) + * + * For this reason do not rely on this function outside a call to + * modifier_reset. + */ + ((pm->bit_depth == 16 || pm->assume_16_bit_calculations) ? + pm->nencodings : 0); /* (4) encodings with gamma == 1.0 */ +} + +static void +modifier_encoding_iterate(png_modifier *pm) +{ + if (!pm->repeat && /* Else something needs the current encoding again. */ + pm->test_uses_encoding) /* Some transform is encoding dependent */ + { + if (pm->test_exhaustive) + { + if (++pm->encoding_counter >= modifier_total_encodings(pm)) + pm->encoding_counter = 0; /* This will stop the repeat */ + } + + else + { + /* Not exhaustive - choose an encoding at random; generate a number in + * the range 1..(max-1), so the result is always non-zero: + */ + if (pm->encoding_counter == 0) + pm->encoding_counter = random_mod(modifier_total_encodings(pm)-1)+1; + else + pm->encoding_counter = 0; + } + + if (pm->encoding_counter > 0) + pm->repeat = 1; + } + + else if (!pm->repeat) + pm->encoding_counter = 0; +} + +static void +modifier_reset(png_modifier *pm) +{ + store_read_reset(&pm->this); + pm->limit = 4E-3; + pm->pending_len = pm->pending_chunk = 0; + pm->flush = pm->buffer_count = pm->buffer_position = 0; + pm->modifications = NULL; + pm->state = modifier_start; + modifier_encoding_iterate(pm); + /* The following must be set in the next run. In particular + * test_uses_encodings must be set in the _ini function of each transform + * that looks at the encodings. (Not the 'add' function!) + */ + pm->test_uses_encoding = 0; + pm->current_gamma = 0; + pm->current_encoding = 0; + pm->encoding_ignored = 0; + /* These only become value after IHDR is read: */ + pm->bit_depth = pm->colour_type = 0; +} + +/* The following must be called before anything else to get the encoding set up + * on the modifier. In particular it must be called before the transform init + * functions are called. + */ +static void +modifier_set_encoding(png_modifier *pm) +{ + /* Set the encoding to the one specified by the current encoding counter, + * first clear out all the settings - this corresponds to an encoding_counter + * of 0. + */ + pm->current_gamma = 0; + pm->current_encoding = 0; + pm->encoding_ignored = 0; /* not ignored yet - happens in _ini functions. */ + + /* Now, if required, set the gamma and encoding fields. */ + if (pm->encoding_counter > 0) + { + /* The gammas[] array is an array of screen gammas, not encoding gammas, + * so we need the inverse: + */ + if (pm->encoding_counter <= pm->ngammas) + pm->current_gamma = 1/pm->gammas[pm->encoding_counter-1]; + + else + { + unsigned int i = pm->encoding_counter - pm->ngammas; + + if (i >= pm->nencodings) + { + i %= pm->nencodings; + pm->current_gamma = 1; /* Linear, only in the 16 bit case */ + } + + else + pm->current_gamma = pm->encodings[i].gamma; + + pm->current_encoding = pm->encodings + i; + } + } +} + +/* Enquiry functions to find out what is set. Notice that there is an implicit + * assumption below that the first encoding in the list is the one for sRGB. + */ +static int +modifier_color_encoding_is_sRGB(PNG_CONST png_modifier *pm) +{ + return pm->current_encoding != 0 && pm->current_encoding == pm->encodings && + pm->current_encoding->gamma == pm->current_gamma; +} + +static int +modifier_color_encoding_is_set(PNG_CONST png_modifier *pm) +{ + return pm->current_gamma != 0; +} + +/* Convenience macros. */ +#define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) +#define CHUNK_IHDR CHUNK(73,72,68,82) +#define CHUNK_PLTE CHUNK(80,76,84,69) +#define CHUNK_IDAT CHUNK(73,68,65,84) +#define CHUNK_IEND CHUNK(73,69,78,68) +#define CHUNK_cHRM CHUNK(99,72,82,77) +#define CHUNK_gAMA CHUNK(103,65,77,65) +#define CHUNK_sBIT CHUNK(115,66,73,84) +#define CHUNK_sRGB CHUNK(115,82,71,66) + +/* The guts of modification are performed during a read. */ +static void +modifier_crc(png_bytep buffer) +{ + /* Recalculate the chunk CRC - a complete chunk must be in + * the buffer, at the start. + */ + uInt datalen = png_get_uint_32(buffer); + uLong crc = crc32(0, buffer+4, datalen+4); + /* The cast to png_uint_32 is safe because a crc32 is always a 32 bit value. + */ + png_save_uint_32(buffer+datalen+8, (png_uint_32)crc); +} + +static void +modifier_setbuffer(png_modifier *pm) +{ + modifier_crc(pm->buffer); + pm->buffer_count = png_get_uint_32(pm->buffer)+12; + pm->buffer_position = 0; +} + +/* Separate the callback into the actual implementation (which is passed the + * png_modifier explicitly) and the callback, which gets the modifier from the + * png_struct. + */ +static void +modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st) +{ + while (st > 0) + { + size_t cb; + png_uint_32 len, chunk; + png_modification *mod; + + if (pm->buffer_position >= pm->buffer_count) switch (pm->state) + { + static png_byte sign[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + case modifier_start: + store_read_imp(&pm->this, pm->buffer, 8); /* size of signature. */ + pm->buffer_count = 8; + pm->buffer_position = 0; + + if (memcmp(pm->buffer, sign, 8) != 0) + png_error(pm->this.pread, "invalid PNG file signature"); + pm->state = modifier_signature; + break; + + case modifier_signature: + store_read_imp(&pm->this, pm->buffer, 13+12); /* size of IHDR */ + pm->buffer_count = 13+12; + pm->buffer_position = 0; + + if (png_get_uint_32(pm->buffer) != 13 || + png_get_uint_32(pm->buffer+4) != CHUNK_IHDR) + png_error(pm->this.pread, "invalid IHDR"); + + /* Check the list of modifiers for modifications to the IHDR. */ + mod = pm->modifications; + while (mod != NULL) + { + if (mod->chunk == CHUNK_IHDR && mod->modify_fn && + (*mod->modify_fn)(pm, mod, 0)) + { + mod->modified = 1; + modifier_setbuffer(pm); + } + + /* Ignore removal or add if IHDR! */ + mod = mod->next; + } + + /* Cache information from the IHDR (the modified one.) */ + pm->bit_depth = pm->buffer[8+8]; + pm->colour_type = pm->buffer[8+8+1]; + + pm->state = modifier_IHDR; + pm->flush = 0; + break; + + case modifier_IHDR: + default: + /* Read a new chunk and process it until we see PLTE, IDAT or + * IEND. 'flush' indicates that there is still some data to + * output from the preceding chunk. + */ + if ((cb = pm->flush) > 0) + { + if (cb > st) cb = st; + pm->flush -= cb; + store_read_imp(&pm->this, pb, cb); + pb += cb; + st -= cb; + if (st == 0) return; + } + + /* No more bytes to flush, read a header, or handle a pending + * chunk. + */ + if (pm->pending_chunk != 0) + { + png_save_uint_32(pm->buffer, pm->pending_len); + png_save_uint_32(pm->buffer+4, pm->pending_chunk); + pm->pending_len = 0; + pm->pending_chunk = 0; + } + else + store_read_imp(&pm->this, pm->buffer, 8); + + pm->buffer_count = 8; + pm->buffer_position = 0; + + /* Check for something to modify or a terminator chunk. */ + len = png_get_uint_32(pm->buffer); + chunk = png_get_uint_32(pm->buffer+4); + + /* Terminators first, they may have to be delayed for added + * chunks + */ + if (chunk == CHUNK_PLTE || chunk == CHUNK_IDAT || + chunk == CHUNK_IEND) + { + mod = pm->modifications; + + while (mod != NULL) + { + if ((mod->add == chunk || + (mod->add == CHUNK_PLTE && chunk == CHUNK_IDAT)) && + mod->modify_fn != NULL && !mod->modified && !mod->added) + { + /* Regardless of what the modify function does do not run + * this again. + */ + mod->added = 1; + + if ((*mod->modify_fn)(pm, mod, 1 /*add*/)) + { + /* Reset the CRC on a new chunk */ + if (pm->buffer_count > 0) + modifier_setbuffer(pm); + + else + { + pm->buffer_position = 0; + mod->removed = 1; + } + + /* The buffer has been filled with something (we assume) + * so output this. Pend the current chunk. + */ + pm->pending_len = len; + pm->pending_chunk = chunk; + break; /* out of while */ + } + } + + mod = mod->next; + } + + /* Don't do any further processing if the buffer was modified - + * otherwise the code will end up modifying a chunk that was + * just added. + */ + if (mod != NULL) + break; /* out of switch */ + } + + /* If we get to here then this chunk may need to be modified. To + * do this it must be less than 1024 bytes in total size, otherwise + * it just gets flushed. + */ + if (len+12 <= sizeof pm->buffer) + { + store_read_imp(&pm->this, pm->buffer+pm->buffer_count, + len+12-pm->buffer_count); + pm->buffer_count = len+12; + + /* Check for a modification, else leave it be. */ + mod = pm->modifications; + while (mod != NULL) + { + if (mod->chunk == chunk) + { + if (mod->modify_fn == NULL) + { + /* Remove this chunk */ + pm->buffer_count = pm->buffer_position = 0; + mod->removed = 1; + break; /* Terminate the while loop */ + } + + else if ((*mod->modify_fn)(pm, mod, 0)) + { + mod->modified = 1; + /* The chunk may have been removed: */ + if (pm->buffer_count == 0) + { + pm->buffer_position = 0; + break; + } + modifier_setbuffer(pm); + } + } + + mod = mod->next; + } + } + + else + pm->flush = len+12 - pm->buffer_count; /* data + crc */ + + /* Take the data from the buffer (if there is any). */ + break; + } + + /* Here to read from the modifier buffer (not directly from + * the store, as in the flush case above.) + */ + cb = pm->buffer_count - pm->buffer_position; + + if (cb > st) + cb = st; + + memcpy(pb, pm->buffer + pm->buffer_position, cb); + st -= cb; + pb += cb; + pm->buffer_position += cb; + } +} + +/* The callback: */ +static void +modifier_read(png_structp ppIn, png_bytep pb, png_size_t st) +{ + png_const_structp pp = ppIn; + png_modifier *pm = voidcast(png_modifier*, png_get_io_ptr(pp)); + + if (pm == NULL || pm->this.pread != pp) + png_error(pp, "bad modifier_read call"); + + modifier_read_imp(pm, pb, st); +} + +/* Like store_progressive_read but the data is getting changed as we go so we + * need a local buffer. + */ +static void +modifier_progressive_read(png_modifier *pm, png_structp pp, png_infop pi) +{ + if (pm->this.pread != pp || pm->this.current == NULL || + pm->this.next == NULL) + png_error(pp, "store state damaged (progressive)"); + + /* This is another Horowitz and Hill random noise generator. In this case + * the aim is to stress the progressive reader with truly horrible variable + * buffer sizes in the range 1..500, so a sequence of 9 bit random numbers + * is generated. We could probably just count from 1 to 32767 and get as + * good a result. + */ + for (;;) + { + static png_uint_32 noise = 1; + png_size_t cb, cbAvail; + png_byte buffer[512]; + + /* Generate 15 more bits of stuff: */ + noise = (noise << 9) | ((noise ^ (noise >> (9-5))) & 0x1ff); + cb = noise & 0x1ff; + + /* Check that this number of bytes are available (in the current buffer.) + * (This doesn't quite work - the modifier might delete a chunk; unlikely + * but possible, it doesn't happen at present because the modifier only + * adds chunks to standard images.) + */ + cbAvail = store_read_buffer_avail(&pm->this); + if (pm->buffer_count > pm->buffer_position) + cbAvail += pm->buffer_count - pm->buffer_position; + + if (cb > cbAvail) + { + /* Check for EOF: */ + if (cbAvail == 0) + break; + + cb = cbAvail; + } + + modifier_read_imp(pm, buffer, cb); + png_process_data(pp, pi, buffer, cb); + } + + /* Check the invariants at the end (if this fails it's a problem in this + * file!) + */ + if (pm->buffer_count > pm->buffer_position || + pm->this.next != &pm->this.current->data || + pm->this.readpos < pm->this.current->datacount) + png_error(pp, "progressive read implementation error"); +} + +/* Set up a modifier. */ +static png_structp +set_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id, + PNG_CONST char *name) +{ + /* Do this first so that the modifier fields are cleared even if an error + * happens allocating the png_struct. No allocation is done here so no + * cleanup is required. + */ + pm->state = modifier_start; + pm->bit_depth = 0; + pm->colour_type = 255; + + pm->pending_len = 0; + pm->pending_chunk = 0; + pm->flush = 0; + pm->buffer_count = 0; + pm->buffer_position = 0; + + return set_store_for_read(&pm->this, ppi, id, name); +} + + +/******************************** MODIFICATIONS *******************************/ +/* Standard modifications to add chunks. These do not require the _SUPPORTED + * macros because the chunks can be there regardless of whether this specific + * libpng supports them. + */ +typedef struct gama_modification +{ + png_modification this; + png_fixed_point gamma; +} gama_modification; + +static int +gama_modify(png_modifier *pm, png_modification *me, int add) +{ + UNUSED(add) + /* This simply dumps the given gamma value into the buffer. */ + png_save_uint_32(pm->buffer, 4); + png_save_uint_32(pm->buffer+4, CHUNK_gAMA); + png_save_uint_32(pm->buffer+8, ((gama_modification*)me)->gamma); + return 1; +} + +static void +gama_modification_init(gama_modification *me, png_modifier *pm, double gammad) +{ + double g; + + modification_init(&me->this); + me->this.chunk = CHUNK_gAMA; + me->this.modify_fn = gama_modify; + me->this.add = CHUNK_PLTE; + g = fix(gammad); + me->gamma = (png_fixed_point)g; + me->this.next = pm->modifications; + pm->modifications = &me->this; +} + +typedef struct chrm_modification +{ + png_modification this; + PNG_CONST color_encoding *encoding; + png_fixed_point wx, wy, rx, ry, gx, gy, bx, by; +} chrm_modification; + +static int +chrm_modify(png_modifier *pm, png_modification *me, int add) +{ + UNUSED(add) + /* As with gAMA this just adds the required cHRM chunk to the buffer. */ + png_save_uint_32(pm->buffer , 32); + png_save_uint_32(pm->buffer+ 4, CHUNK_cHRM); + png_save_uint_32(pm->buffer+ 8, ((chrm_modification*)me)->wx); + png_save_uint_32(pm->buffer+12, ((chrm_modification*)me)->wy); + png_save_uint_32(pm->buffer+16, ((chrm_modification*)me)->rx); + png_save_uint_32(pm->buffer+20, ((chrm_modification*)me)->ry); + png_save_uint_32(pm->buffer+24, ((chrm_modification*)me)->gx); + png_save_uint_32(pm->buffer+28, ((chrm_modification*)me)->gy); + png_save_uint_32(pm->buffer+32, ((chrm_modification*)me)->bx); + png_save_uint_32(pm->buffer+36, ((chrm_modification*)me)->by); + return 1; +} + +static void +chrm_modification_init(chrm_modification *me, png_modifier *pm, + PNG_CONST color_encoding *encoding) +{ + CIE_color white = white_point(encoding); + + /* Original end points: */ + me->encoding = encoding; + + /* Chromaticities (in fixed point): */ + me->wx = fix(chromaticity_x(white)); + me->wy = fix(chromaticity_y(white)); + + me->rx = fix(chromaticity_x(encoding->red)); + me->ry = fix(chromaticity_y(encoding->red)); + me->gx = fix(chromaticity_x(encoding->green)); + me->gy = fix(chromaticity_y(encoding->green)); + me->bx = fix(chromaticity_x(encoding->blue)); + me->by = fix(chromaticity_y(encoding->blue)); + + modification_init(&me->this); + me->this.chunk = CHUNK_cHRM; + me->this.modify_fn = chrm_modify; + me->this.add = CHUNK_PLTE; + me->this.next = pm->modifications; + pm->modifications = &me->this; +} + +typedef struct srgb_modification +{ + png_modification this; + png_byte intent; +} srgb_modification; + +static int +srgb_modify(png_modifier *pm, png_modification *me, int add) +{ + UNUSED(add) + /* As above, ignore add and just make a new chunk */ + png_save_uint_32(pm->buffer, 1); + png_save_uint_32(pm->buffer+4, CHUNK_sRGB); + pm->buffer[8] = ((srgb_modification*)me)->intent; + return 1; +} + +static void +srgb_modification_init(srgb_modification *me, png_modifier *pm, png_byte intent) +{ + modification_init(&me->this); + me->this.chunk = CHUNK_sBIT; + + if (intent <= 3) /* if valid, else *delete* sRGB chunks */ + { + me->this.modify_fn = srgb_modify; + me->this.add = CHUNK_PLTE; + me->intent = intent; + } + + else + { + me->this.modify_fn = 0; + me->this.add = 0; + me->intent = 0; + } + + me->this.next = pm->modifications; + pm->modifications = &me->this; +} + +#ifdef PNG_READ_GAMMA_SUPPORTED +typedef struct sbit_modification +{ + png_modification this; + png_byte sbit; +} sbit_modification; + +static int +sbit_modify(png_modifier *pm, png_modification *me, int add) +{ + png_byte sbit = ((sbit_modification*)me)->sbit; + if (pm->bit_depth > sbit) + { + int cb = 0; + switch (pm->colour_type) + { + case 0: + cb = 1; + break; + + case 2: + case 3: + cb = 3; + break; + + case 4: + cb = 2; + break; + + case 6: + cb = 4; + break; + + default: + png_error(pm->this.pread, + "unexpected colour type in sBIT modification"); + } + + png_save_uint_32(pm->buffer, cb); + png_save_uint_32(pm->buffer+4, CHUNK_sBIT); + + while (cb > 0) + (pm->buffer+8)[--cb] = sbit; + + return 1; + } + else if (!add) + { + /* Remove the sBIT chunk */ + pm->buffer_count = pm->buffer_position = 0; + return 1; + } + else + return 0; /* do nothing */ +} + +static void +sbit_modification_init(sbit_modification *me, png_modifier *pm, png_byte sbit) +{ + modification_init(&me->this); + me->this.chunk = CHUNK_sBIT; + me->this.modify_fn = sbit_modify; + me->this.add = CHUNK_PLTE; + me->sbit = sbit; + me->this.next = pm->modifications; + pm->modifications = &me->this; +} +#endif /* PNG_READ_GAMMA_SUPPORTED */ +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +/***************************** STANDARD PNG FILES *****************************/ +/* Standard files - write and save standard files. */ +/* There are two basic forms of standard images. Those which attempt to have + * all the possible pixel values (not possible for 16bpp images, but a range of + * values are produced) and those which have a range of image sizes. The former + * are used for testing transforms, in particular gamma correction and bit + * reduction and increase. The latter are reserved for testing the behavior of + * libpng with respect to 'odd' image sizes - particularly small images where + * rows become 1 byte and interlace passes disappear. + * + * The first, most useful, set are the 'transform' images, the second set of + * small images are the 'size' images. + * + * The transform files are constructed with rows which fit into a 1024 byte row + * buffer. This makes allocation easier below. Further regardless of the file + * format every row has 128 pixels (giving 1024 bytes for 64bpp formats). + * + * Files are stored with no gAMA or sBIT chunks, with a PLTE only when needed + * and with an ID derived from the colour type, bit depth and interlace type + * as above (FILEID). The width (128) and height (variable) are not stored in + * the FILEID - instead the fields are set to 0, indicating a transform file. + * + * The size files ar constructed with rows a maximum of 128 bytes wide, allowing + * a maximum width of 16 pixels (for the 64bpp case.) They also have a maximum + * height of 16 rows. The width and height are stored in the FILEID and, being + * non-zero, indicate a size file. + * + * For palette image (colour type 3) multiple transform images are stored with + * the same bit depth to allow testing of more colour combinations - + * particularly important for testing the gamma code because libpng uses a + * different code path for palette images. For size images a single palette is + * used. + */ + +/* Make a 'standard' palette. Because there are only 256 entries in a palette + * (maximum) this actually makes a random palette in the hope that enough tests + * will catch enough errors. (Note that the same palette isn't produced every + * time for the same test - it depends on what previous tests have been run - + * but a given set of arguments to pngvalid will always produce the same palette + * at the same test! This is why pseudo-random number generators are useful for + * testing.) + * + * The store must be open for write when this is called, otherwise an internal + * error will occur. This routine contains its own magic number seed, so the + * palettes generated don't change if there are intervening errors (changing the + * calls to the store_mark seed.) + */ +static store_palette_entry * +make_standard_palette(png_store* ps, int npalette, int do_tRNS) +{ + static png_uint_32 palette_seed[2] = { 0x87654321, 9 }; + + int i = 0; + png_byte values[256][4]; + + /* Always put in black and white plus the six primary and secondary colors. + */ + for (; i<8; ++i) + { + values[i][1] = (png_byte)((i&1) ? 255U : 0U); + values[i][2] = (png_byte)((i&2) ? 255U : 0U); + values[i][3] = (png_byte)((i&4) ? 255U : 0U); + } + + /* Then add 62 grays (one quarter of the remaining 256 slots). */ + { + int j = 0; + png_byte random_bytes[4]; + png_byte need[256]; + + need[0] = 0; /*got black*/ + memset(need+1, 1, (sizeof need)-2); /*need these*/ + need[255] = 0; /*but not white*/ + + while (i<70) + { + png_byte b; + + if (j==0) + { + make_four_random_bytes(palette_seed, random_bytes); + j = 4; + } + + b = random_bytes[--j]; + if (need[b]) + { + values[i][1] = b; + values[i][2] = b; + values[i++][3] = b; + } + } + } + + /* Finally add 192 colors at random - don't worry about matches to things we + * already have, chance is less than 1/65536. Don't worry about grays, + * chance is the same, so we get a duplicate or extra gray less than 1 time + * in 170. + */ + for (; i<256; ++i) + make_four_random_bytes(palette_seed, values[i]); + + /* Fill in the alpha values in the first byte. Just use all possible values + * (0..255) in an apparently random order: + */ + { + store_palette_entry *palette; + png_byte selector[4]; + + make_four_random_bytes(palette_seed, selector); + + if (do_tRNS) + for (i=0; i<256; ++i) + values[i][0] = (png_byte)(i ^ selector[0]); + + else + for (i=0; i<256; ++i) + values[i][0] = 255; /* no transparency/tRNS chunk */ + + /* 'values' contains 256 ARGB values, but we only need 'npalette'. + * 'npalette' will always be a power of 2: 2, 4, 16 or 256. In the low + * bit depth cases select colors at random, else it is difficult to have + * a set of low bit depth palette test with any chance of a reasonable + * range of colors. Do this by randomly permuting values into the low + * 'npalette' entries using an XOR mask generated here. This also + * permutes the npalette == 256 case in a potentially useful way (there is + * no relationship between palette index and the color value therein!) + */ + palette = store_write_palette(ps, npalette); + + for (i=0; i 0) + png_set_tRNS(pp, pi, tRNS, j, 0/*color*/); + } +} + +/* The number of passes is related to the interlace type. There was no libpng + * API to determine this prior to 1.5, so we need an inquiry function: + */ +static int +npasses_from_interlace_type(png_const_structp pp, int interlace_type) +{ + switch (interlace_type) + { + default: + png_error(pp, "invalid interlace type"); + + case PNG_INTERLACE_NONE: + return 1; + + case PNG_INTERLACE_ADAM7: + return PNG_INTERLACE_ADAM7_PASSES; + } +} + +static unsigned int +bit_size(png_const_structp pp, png_byte colour_type, png_byte bit_depth) +{ + switch (colour_type) + { + default: png_error(pp, "invalid color type"); + + case 0: return bit_depth; + + case 2: return 3*bit_depth; + + case 3: return bit_depth; + + case 4: return 2*bit_depth; + + case 6: return 4*bit_depth; + } +} + +#define TRANSFORM_WIDTH 128U +#define TRANSFORM_ROWMAX (TRANSFORM_WIDTH*8U) +#define SIZE_ROWMAX (16*8U) /* 16 pixels, max 8 bytes each - 128 bytes */ +#define STANDARD_ROWMAX TRANSFORM_ROWMAX /* The larger of the two */ +#define SIZE_HEIGHTMAX 16 /* Maximum range of size images */ + +static size_t +transform_rowsize(png_const_structp pp, png_byte colour_type, + png_byte bit_depth) +{ + return (TRANSFORM_WIDTH * bit_size(pp, colour_type, bit_depth)) / 8; +} + +/* transform_width(pp, colour_type, bit_depth) current returns the same number + * every time, so just use a macro: + */ +#define transform_width(pp, colour_type, bit_depth) TRANSFORM_WIDTH + +static png_uint_32 +transform_height(png_const_structp pp, png_byte colour_type, png_byte bit_depth) +{ + switch (bit_size(pp, colour_type, bit_depth)) + { + case 1: + case 2: + case 4: + return 1; /* Total of 128 pixels */ + + case 8: + return 2; /* Total of 256 pixels/bytes */ + + case 16: + return 512; /* Total of 65536 pixels */ + + case 24: + case 32: + return 512; /* 65536 pixels */ + + case 48: + case 64: + return 2048;/* 4 x 65536 pixels. */ +# define TRANSFORM_HEIGHTMAX 2048 + + default: + return 0; /* Error, will be caught later */ + } +} + +#ifdef PNG_READ_SUPPORTED +/* The following can only be defined here, now we have the definitions + * of the transform image sizes. + */ +static png_uint_32 +standard_width(png_const_structp pp, png_uint_32 id) +{ + png_uint_32 width = WIDTH_FROM_ID(id); + UNUSED(pp) + + if (width == 0) + width = transform_width(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); + + return width; +} + +static png_uint_32 +standard_height(png_const_structp pp, png_uint_32 id) +{ + png_uint_32 height = HEIGHT_FROM_ID(id); + + if (height == 0) + height = transform_height(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); + + return height; +} + +static png_uint_32 +standard_rowsize(png_const_structp pp, png_uint_32 id) +{ + png_uint_32 width = standard_width(pp, id); + + /* This won't overflow: */ + width *= bit_size(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); + return (width + 7) / 8; +} +#endif /* PNG_READ_SUPPORTED */ + +static void +transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], + png_byte colour_type, png_byte bit_depth, png_uint_32 y) +{ + png_uint_32 v = y << 7; + png_uint_32 i = 0; + + switch (bit_size(pp, colour_type, bit_depth)) + { + case 1: + while (i<128/8) buffer[i] = (png_byte)(v & 0xff), v += 17, ++i; + return; + + case 2: + while (i<128/4) buffer[i] = (png_byte)(v & 0xff), v += 33, ++i; + return; + + case 4: + while (i<128/2) buffer[i] = (png_byte)(v & 0xff), v += 65, ++i; + return; + + case 8: + /* 256 bytes total, 128 bytes in each row set as follows: */ + while (i<128) buffer[i] = (png_byte)(v & 0xff), ++v, ++i; + return; + + case 16: + /* Generate all 65536 pixel values in order, which includes the 8 bit + * GA case as well as the 16 bit G case. + */ + while (i<128) + { + buffer[2*i] = (png_byte)((v>>8) & 0xff); + buffer[2*i+1] = (png_byte)(v & 0xff); + ++v; + ++i; + } + + return; + + case 24: + /* 65535 pixels, but rotate the values. */ + while (i<128) + { + /* Three bytes per pixel, r, g, b, make b by r^g */ + buffer[3*i+0] = (png_byte)((v >> 8) & 0xff); + buffer[3*i+1] = (png_byte)(v & 0xff); + buffer[3*i+2] = (png_byte)(((v >> 8) ^ v) & 0xff); + ++v; + ++i; + } + + return; + + case 32: + /* 65535 pixels, r, g, b, a; just replicate */ + while (i<128) + { + buffer[4*i+0] = (png_byte)((v >> 8) & 0xff); + buffer[4*i+1] = (png_byte)(v & 0xff); + buffer[4*i+2] = (png_byte)((v >> 8) & 0xff); + buffer[4*i+3] = (png_byte)(v & 0xff); + ++v; + ++i; + } + + return; + + case 48: + /* y is maximum 2047, giving 4x65536 pixels, make 'r' increase by 1 at + * each pixel, g increase by 257 (0x101) and 'b' by 0x1111: + */ + while (i<128) + { + png_uint_32 t = v++; + buffer[6*i+0] = (png_byte)((t >> 8) & 0xff); + buffer[6*i+1] = (png_byte)(t & 0xff); + t *= 257; + buffer[6*i+2] = (png_byte)((t >> 8) & 0xff); + buffer[6*i+3] = (png_byte)(t & 0xff); + t *= 17; + buffer[6*i+4] = (png_byte)((t >> 8) & 0xff); + buffer[6*i+5] = (png_byte)(t & 0xff); + ++i; + } + + return; + + case 64: + /* As above in the 32 bit case. */ + while (i<128) + { + png_uint_32 t = v++; + buffer[8*i+0] = (png_byte)((t >> 8) & 0xff); + buffer[8*i+1] = (png_byte)(t & 0xff); + buffer[8*i+4] = (png_byte)((t >> 8) & 0xff); + buffer[8*i+5] = (png_byte)(t & 0xff); + t *= 257; + buffer[8*i+2] = (png_byte)((t >> 8) & 0xff); + buffer[8*i+3] = (png_byte)(t & 0xff); + buffer[8*i+6] = (png_byte)((t >> 8) & 0xff); + buffer[8*i+7] = (png_byte)(t & 0xff); + ++i; + } + return; + + default: + break; + } + + png_error(pp, "internal error"); +} + +/* This is just to do the right cast - could be changed to a function to check + * 'bd' but there isn't much point. + */ +#define DEPTH(bd) ((png_byte)(1U << (bd))) + +/* Make a standardized image given a an image colour type, bit depth and + * interlace type. The standard images have a very restricted range of + * rows and heights and are used for testing transforms rather than image + * layout details. See make_size_images below for a way to make images + * that test odd sizes along with the libpng interlace handling. + */ +static void +make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, + png_byte PNG_CONST bit_depth, unsigned int palette_number, + int interlace_type, png_const_charp name) +{ + context(ps, fault); + + Try + { + png_infop pi; + png_structp pp = set_store_for_write(ps, &pi, name); + png_uint_32 h; + + /* In the event of a problem return control to the Catch statement below + * to do the clean up - it is not possible to 'return' directly from a Try + * block. + */ + if (pp == NULL) + Throw ps; + + h = transform_height(pp, colour_type, bit_depth); + + png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), h, + bit_depth, colour_type, interlace_type, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + +#ifdef PNG_TEXT_SUPPORTED +# if defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED) +# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_zTXt +# else +# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_NONE +# endif + { + static char key[] = "image name"; /* must be writeable */ + size_t pos; + png_text text; + char copy[FILE_NAME_SIZE]; + + /* Use a compressed text string to test the correct interaction of text + * compression and IDAT compression. + */ + text.compression = TEXT_COMPRESSION; + text.key = key; + /* Yuck: the text must be writable! */ + pos = safecat(copy, sizeof copy, 0, ps->wname); + text.text = copy; + text.text_length = pos; + text.itxt_length = 0; + text.lang = 0; + text.lang_key = 0; + + png_set_text(pp, pi, &text, 1); + } +#endif + + if (colour_type == 3) /* palette */ + init_standard_palette(ps, pp, pi, 1U << bit_depth, 1/*do tRNS*/); + + png_write_info(pp, pi); + + if (png_get_rowbytes(pp, pi) != + transform_rowsize(pp, colour_type, bit_depth)) + png_error(pp, "row size incorrect"); + + else + { + /* Somewhat confusingly this must be called *after* png_write_info + * because if it is called before, the information in *pp has not been + * updated to reflect the interlaced image. + */ + int npasses = png_set_interlace_handling(pp); + int pass; + + if (npasses != npasses_from_interlace_type(pp, interlace_type)) + png_error(pp, "write: png_set_interlace_handling failed"); + + for (pass=0; passtest, sizeof ps->test, 0, "make standard images"); + + /* Use next_format to enumerate all the combinations we test, including + * generating multiple low bit depth palette images. + */ + while (next_format(&colour_type, &bit_depth, &palette_number)) + { + int interlace_type; + + for (interlace_type = PNG_INTERLACE_NONE; + interlace_type < PNG_INTERLACE_LAST; ++interlace_type) + { + char name[FILE_NAME_SIZE]; + + standard_name(name, sizeof name, 0, colour_type, bit_depth, + palette_number, interlace_type, 0, 0, 0); + make_transform_image(ps, colour_type, bit_depth, palette_number, + interlace_type, name); + } + } +} + +/* The following two routines use the PNG interlace support macros from + * png.h to interlace or deinterlace rows. + */ +static void +interlace_row(png_bytep buffer, png_const_bytep imageRow, + unsigned int pixel_size, png_uint_32 w, int pass) +{ + png_uint_32 xin, xout, xstep; + + /* Note that this can, trivially, be optimized to a memcpy on pass 7, the + * code is presented this way to make it easier to understand. In practice + * consult the code in the libpng source to see other ways of doing this. + */ + xin = PNG_PASS_START_COL(pass); + xstep = 1U<= 8) + *buffer++ = (png_byte)y++, bit_width -= 8; + + /* There may be up to 7 remaining bits, these go in the most significant + * bits of the byte. + */ + if (bit_width > 0) + { + png_uint_32 mask = (1U<<(8-bit_width))-1; + *buffer = (png_byte)((*buffer & mask) | (y & ~mask)); + } +} + +static void +make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, + png_byte PNG_CONST bit_depth, int PNG_CONST interlace_type, + png_uint_32 PNG_CONST w, png_uint_32 PNG_CONST h, + int PNG_CONST do_interlace) +{ + context(ps, fault); + + Try + { + png_infop pi; + png_structp pp; + unsigned int pixel_size; + + /* Make a name and get an appropriate id for the store: */ + char name[FILE_NAME_SIZE]; + PNG_CONST png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/, + interlace_type, w, h, do_interlace); + + standard_name_from_id(name, sizeof name, 0, id); + pp = set_store_for_write(ps, &pi, name); + + /* In the event of a problem return control to the Catch statement below + * to do the clean up - it is not possible to 'return' directly from a Try + * block. + */ + if (pp == NULL) + Throw ps; + + png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + +#ifdef PNG_TEXT_SUPPORTED + { + static char key[] = "image name"; /* must be writeable */ + size_t pos; + png_text text; + char copy[FILE_NAME_SIZE]; + + /* Use a compressed text string to test the correct interaction of text + * compression and IDAT compression. + */ + text.compression = TEXT_COMPRESSION; + text.key = key; + /* Yuck: the text must be writable! */ + pos = safecat(copy, sizeof copy, 0, ps->wname); + text.text = copy; + text.text_length = pos; + text.itxt_length = 0; + text.lang = 0; + text.lang_key = 0; + + png_set_text(pp, pi, &text, 1); + } +#endif + + if (colour_type == 3) /* palette */ + init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/); + + png_write_info(pp, pi); + + /* Calculate the bit size, divide by 8 to get the byte size - this won't + * overflow because we know the w values are all small enough even for + * a system where 'unsigned int' is only 16 bits. + */ + pixel_size = bit_size(pp, colour_type, bit_depth); + if (png_get_rowbytes(pp, pi) != ((w * pixel_size) + 7) / 8) + png_error(pp, "row size incorrect"); + + else + { + int npasses = npasses_from_interlace_type(pp, interlace_type); + png_uint_32 y; + int pass; + png_byte image[16][SIZE_ROWMAX]; + + /* To help consistent error detection make the parts of this buffer + * that aren't set below all '1': + */ + memset(image, 0xff, sizeof image); + + if (!do_interlace && npasses != png_set_interlace_handling(pp)) + png_error(pp, "write: png_set_interlace_handling failed"); + + /* Prepare the whole image first to avoid making it 7 times: */ + for (y=0; y 0) + { + /* Set to all 1's for error detection (libpng tends to + * set unset things to 0). + */ + memset(tempRow, 0xff, sizeof tempRow); + interlace_row(tempRow, row, pixel_size, w, pass); + row = tempRow; + } + else + continue; + } + + /* Only get to here if the row has some pixels in it. */ + png_write_row(pp, row); + } + } + } + +#ifdef PNG_TEXT_SUPPORTED + { + static char key[] = "end marker"; + static char comment[] = "end"; + png_text text; + + /* Use a compressed text string to test the correct interaction of text + * compression and IDAT compression. + */ + text.compression = TEXT_COMPRESSION; + text.key = key; + text.text = comment; + text.text_length = (sizeof comment)-1; + text.itxt_length = 0; + text.lang = 0; + text.lang_key = 0; + + png_set_text(pp, pi, &text, 1); + } +#endif + + png_write_end(pp, pi); + + /* And store this under the appropriate id, then clean up. */ + store_storefile(ps, id); + + store_write_reset(ps); + } + + Catch(fault) + { + /* Use the png_store returned by the exception. This may help the compiler + * because 'ps' is not used in this branch of the setjmp. Note that fault + * and ps will always be the same value. + */ + store_write_reset(fault); + } +} + +static void +make_size(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo, + int PNG_CONST bdhi) +{ + for (; bdlo <= bdhi; ++bdlo) + { + png_uint_32 width; + + for (width = 1; width <= 16; ++width) + { + png_uint_32 height; + + for (height = 1; height <= 16; ++height) + { + /* The four combinations of DIY interlace and interlace or not - + * no interlace + DIY should be identical to no interlace with + * libpng doing it. + */ + make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_NONE, + width, height, 0); + make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_NONE, + width, height, 1); + make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, + width, height, 0); + make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, + width, height, 1); + } + } + } +} + +static void +make_size_images(png_store *ps) +{ + /* This is in case of errors. */ + safecat(ps->test, sizeof ps->test, 0, "make size images"); + + /* Arguments are colour_type, low bit depth, high bit depth + */ + make_size(ps, 0, 0, WRITE_BDHI); + make_size(ps, 2, 3, WRITE_BDHI); + make_size(ps, 3, 0, 3 /*palette: max 8 bits*/); + make_size(ps, 4, 3, WRITE_BDHI); + make_size(ps, 6, 3, WRITE_BDHI); +} + +#ifdef PNG_READ_SUPPORTED +/* Return a row based on image id and 'y' for checking: */ +static void +standard_row(png_const_structp pp, png_byte std[STANDARD_ROWMAX], + png_uint_32 id, png_uint_32 y) +{ + if (WIDTH_FROM_ID(id) == 0) + transform_row(pp, std, COL_FROM_ID(id), DEPTH_FROM_ID(id), y); + else + size_row(std, WIDTH_FROM_ID(id) * bit_size(pp, COL_FROM_ID(id), + DEPTH_FROM_ID(id)), y); +} +#endif /* PNG_READ_SUPPORTED */ + +/* Tests - individual test cases */ +/* Like 'make_standard' but errors are deliberately introduced into the calls + * to ensure that they get detected - it should not be possible to write an + * invalid image with libpng! + */ +/* TODO: the 'set' functions can probably all be made to take a + * png_const_structp rather than a modifiable one. + */ +#ifdef PNG_WARNINGS_SUPPORTED +static void +sBIT0_error_fn(png_structp pp, png_infop pi) +{ + /* 0 is invalid... */ + png_color_8 bad; + bad.red = bad.green = bad.blue = bad.gray = bad.alpha = 0; + png_set_sBIT(pp, pi, &bad); +} + +static void +sBIT_error_fn(png_structp pp, png_infop pi) +{ + png_byte bit_depth; + png_color_8 bad; + + if (png_get_color_type(pp, pi) == PNG_COLOR_TYPE_PALETTE) + bit_depth = 8; + + else + bit_depth = png_get_bit_depth(pp, pi); + + /* Now we know the bit depth we can easily generate an invalid sBIT entry */ + bad.red = bad.green = bad.blue = bad.gray = bad.alpha = + (png_byte)(bit_depth+1); + png_set_sBIT(pp, pi, &bad); +} + +static PNG_CONST struct +{ + void (*fn)(png_structp, png_infop); + PNG_CONST char *msg; + unsigned int warning :1; /* the error is a warning... */ +} error_test[] = + { + /* no warnings makes these errors undetectable. */ + { sBIT0_error_fn, "sBIT(0): failed to detect error", 1 }, + { sBIT_error_fn, "sBIT(too big): failed to detect error", 1 }, + }; + +static void +make_error(png_store* volatile psIn, png_byte PNG_CONST colour_type, + png_byte bit_depth, int interlace_type, int test, png_const_charp name) +{ + png_store * volatile ps = psIn; + + context(ps, fault); + + Try + { + png_structp pp; + png_infop pi; + + pp = set_store_for_write(ps, &pi, name); + + if (pp == NULL) + Throw ps; + + png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), + transform_height(pp, colour_type, bit_depth), bit_depth, colour_type, + interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + if (colour_type == 3) /* palette */ + init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/); + + /* Time for a few errors; these are in various optional chunks, the + * standard tests test the standard chunks pretty well. + */ +# define exception__prev exception_prev_1 +# define exception__env exception_env_1 + Try + { + /* Expect this to throw: */ + ps->expect_error = !error_test[test].warning; + ps->expect_warning = error_test[test].warning; + ps->saw_warning = 0; + error_test[test].fn(pp, pi); + + /* Normally the error is only detected here: */ + png_write_info(pp, pi); + + /* And handle the case where it was only a warning: */ + if (ps->expect_warning && ps->saw_warning) + Throw ps; + + /* If we get here there is a problem, we have success - no error or + * no warning - when we shouldn't have success. Log an error. + */ + store_log(ps, pp, error_test[test].msg, 1 /*error*/); + } + + Catch (fault) + ps = fault; /* expected exit, make sure ps is not clobbered */ +#undef exception__prev +#undef exception__env + + /* And clear these flags */ + ps->expect_error = 0; + ps->expect_warning = 0; + + /* Now write the whole image, just to make sure that the detected, or + * undetected, errro has not created problems inside libpng. + */ + if (png_get_rowbytes(pp, pi) != + transform_rowsize(pp, colour_type, bit_depth)) + png_error(pp, "row size incorrect"); + + else + { + png_uint_32 h = transform_height(pp, colour_type, bit_depth); + int npasses = png_set_interlace_handling(pp); + int pass; + + if (npasses != npasses_from_interlace_type(pp, interlace_type)) + png_error(pp, "write: png_set_interlace_handling failed"); + + for (pass=0; passthis, colour_type, DEPTH(bdlo), interlace_type, + test, name); + + if (fail(pm)) + return 0; + } + } + } + + return 1; /* keep going */ +} +#endif + +static void +perform_error_test(png_modifier *pm) +{ +#ifdef PNG_WARNINGS_SUPPORTED /* else there are no cases that work! */ + /* Need to do this here because we just write in this test. */ + safecat(pm->this.test, sizeof pm->this.test, 0, "error test"); + + if (!make_errors(pm, 0, 0, WRITE_BDHI)) + return; + + if (!make_errors(pm, 2, 3, WRITE_BDHI)) + return; + + if (!make_errors(pm, 3, 0, 3)) + return; + + if (!make_errors(pm, 4, 3, WRITE_BDHI)) + return; + + if (!make_errors(pm, 6, 3, WRITE_BDHI)) + return; +#else + UNUSED(pm) +#endif +} + +/* This is just to validate the internal PNG formatting code - if this fails + * then the warning messages the library outputs will probably be garbage. + */ +static void +perform_formatting_test(png_store *volatile ps) +{ +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* The handle into the formatting code is the RFC1123 support; this test does + * nothing if that is compiled out. + */ + context(ps, fault); + + Try + { + png_const_charp correct = "29 Aug 2079 13:53:60 +0000"; + png_const_charp result; +# if PNG_LIBPNG_VER >= 10600 + char timestring[29]; +# endif + png_structp pp; + png_time pt; + + pp = set_store_for_write(ps, NULL, "libpng formatting test"); + + if (pp == NULL) + Throw ps; + + + /* Arbitrary settings: */ + pt.year = 2079; + pt.month = 8; + pt.day = 29; + pt.hour = 13; + pt.minute = 53; + pt.second = 60; /* a leap second */ + +# if PNG_LIBPNG_VER < 10600 + result = png_convert_to_rfc1123(pp, &pt); +# else + if (png_convert_to_rfc1123_buffer(timestring, &pt)) + result = timestring; + + else + result = NULL; +# endif + + if (result == NULL) + png_error(pp, "png_convert_to_rfc1123 failed"); + + if (strcmp(result, correct) != 0) + { + size_t pos = 0; + char msg[128]; + + pos = safecat(msg, sizeof msg, pos, "png_convert_to_rfc1123("); + pos = safecat(msg, sizeof msg, pos, correct); + pos = safecat(msg, sizeof msg, pos, ") returned: '"); + pos = safecat(msg, sizeof msg, pos, result); + pos = safecat(msg, sizeof msg, pos, "'"); + + png_error(pp, msg); + } + + store_write_reset(ps); + } + + Catch(fault) + { + store_write_reset(fault); + } +#else + UNUSED(ps) +#endif +} + +#ifdef PNG_READ_SUPPORTED +/* Because we want to use the same code in both the progressive reader and the + * sequential reader it is necessary to deal with the fact that the progressive + * reader callbacks only have one parameter (png_get_progressive_ptr()), so this + * must contain all the test parameters and all the local variables directly + * accessible to the sequential reader implementation. + * + * The technique adopted is to reinvent part of what Dijkstra termed a + * 'display'; an array of pointers to the stack frames of enclosing functions so + * that a nested function definition can access the local (C auto) variables of + * the functions that contain its definition. In fact C provides the first + * pointer (the local variables - the stack frame pointer) and the last (the + * global variables - the BCPL global vector typically implemented as global + * addresses), this code requires one more pointer to make the display - the + * local variables (and function call parameters) of the function that actually + * invokes either the progressive or sequential reader. + * + * Perhaps confusingly this technique is confounded with classes - the + * 'standard_display' defined here is sub-classed as the 'gamma_display' below. + * A gamma_display is a standard_display, taking advantage of the ANSI-C + * requirement that the pointer to the first member of a structure must be the + * same as the pointer to the structure. This allows us to reuse standard_ + * functions in the gamma test code; something that could not be done with + * nested functions! + */ +typedef struct standard_display +{ + png_store* ps; /* Test parameters (passed to the function) */ + png_byte colour_type; + png_byte bit_depth; + png_byte red_sBIT; /* Input data sBIT values. */ + png_byte green_sBIT; + png_byte blue_sBIT; + png_byte alpha_sBIT; + int interlace_type; + png_uint_32 id; /* Calculated file ID */ + png_uint_32 w; /* Width of image */ + png_uint_32 h; /* Height of image */ + int npasses; /* Number of interlaced passes */ + png_uint_32 pixel_size; /* Width of one pixel in bits */ + png_uint_32 bit_width; /* Width of output row in bits */ + size_t cbRow; /* Bytes in a row of the output image */ + int do_interlace; /* Do interlacing internally */ + int is_transparent; /* Transparency information was present. */ + int speed; /* Doing a speed test */ + int use_update_info;/* Call update_info, not start_image */ + struct + { + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + } transparent; /* The transparent color, if set. */ + int npalette; /* Number of entries in the palette. */ + store_palette + palette; +} standard_display; + +static void +standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id, + int do_interlace, int use_update_info) +{ + memset(dp, 0, sizeof *dp); + + dp->ps = ps; + dp->colour_type = COL_FROM_ID(id); + dp->bit_depth = DEPTH_FROM_ID(id); + if (dp->bit_depth < 1 || dp->bit_depth > 16) + internal_error(ps, "internal: bad bit depth"); + if (dp->colour_type == 3) + dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = 8; + else + dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = + dp->bit_depth; + dp->interlace_type = INTERLACE_FROM_ID(id); + dp->id = id; + /* All the rest are filled in after the read_info: */ + dp->w = 0; + dp->h = 0; + dp->npasses = 0; + dp->pixel_size = 0; + dp->bit_width = 0; + dp->cbRow = 0; + dp->do_interlace = do_interlace; + dp->is_transparent = 0; + dp->speed = ps->speed; + dp->use_update_info = use_update_info; + dp->npalette = 0; + /* Preset the transparent color to black: */ + memset(&dp->transparent, 0, sizeof dp->transparent); + /* Preset the palette to full intensity/opaque througout: */ + memset(dp->palette, 0xff, sizeof dp->palette); +} + +/* Initialize the palette fields - this must be done later because the palette + * comes from the particular png_store_file that is selected. + */ +static void +standard_palette_init(standard_display *dp) +{ + store_palette_entry *palette = store_current_palette(dp->ps, &dp->npalette); + + /* The remaining entries remain white/opaque. */ + if (dp->npalette > 0) + { + int i = dp->npalette; + memcpy(dp->palette, palette, i * sizeof *palette); + + /* Check for a non-opaque palette entry: */ + while (--i >= 0) + if (palette[i].alpha < 255) + break; + +# ifdef __GNUC__ + /* GCC can't handle the more obviously optimizable version. */ + if (i >= 0) + dp->is_transparent = 1; + else + dp->is_transparent = 0; +# else + dp->is_transparent = (i >= 0); +# endif + } +} + +/* Utility to read the palette from the PNG file and convert it into + * store_palette format. This returns 1 if there is any transparency in the + * palette (it does not check for a transparent colour in the non-palette case.) + */ +static int +read_palette(store_palette palette, int *npalette, png_const_structp pp, + png_infop pi) +{ + png_colorp pal; + png_bytep trans_alpha; + int num; + + pal = 0; + *npalette = -1; + + if (png_get_PLTE(pp, pi, &pal, npalette) & PNG_INFO_PLTE) + { + int i = *npalette; + + if (i <= 0 || i > 256) + png_error(pp, "validate: invalid PLTE count"); + + while (--i >= 0) + { + palette[i].red = pal[i].red; + palette[i].green = pal[i].green; + palette[i].blue = pal[i].blue; + } + + /* Mark the remainder of the entries with a flag value (other than + * white/opaque which is the flag value stored above.) + */ + memset(palette + *npalette, 126, (256-*npalette) * sizeof *palette); + } + + else /* !png_get_PLTE */ + { + if (*npalette != (-1)) + png_error(pp, "validate: invalid PLTE result"); + /* But there is no palette, so record this: */ + *npalette = 0; + memset(palette, 113, sizeof (store_palette)); + } + + trans_alpha = 0; + num = 2; /* force error below */ + if ((png_get_tRNS(pp, pi, &trans_alpha, &num, 0) & PNG_INFO_tRNS) != 0 && + (trans_alpha != NULL || num != 1/*returns 1 for a transparent color*/) && + /* Oops, if a palette tRNS gets expanded png_read_update_info (at least so + * far as 1.5.4) does not remove the trans_alpha pointer, only num_trans, + * so in the above call we get a success, we get a pointer (who knows what + * to) and we get num_trans == 0: + */ + !(trans_alpha != NULL && num == 0)) /* TODO: fix this in libpng. */ + { + int i; + + /* Any of these are crash-worthy - given the implementation of + * png_get_tRNS up to 1.5 an app won't crash if it just checks the + * result above and fails to check that the variables it passed have + * actually been filled in! Note that if the app were to pass the + * last, png_color_16p, variable too it couldn't rely on this. + */ + if (trans_alpha == NULL || num <= 0 || num > 256 || num > *npalette) + png_error(pp, "validate: unexpected png_get_tRNS (palette) result"); + + for (i=0; iis_transparent) + png_error(pp, "validate: palette transparency changed"); + + if (npalette != dp->npalette) + { + size_t pos = 0; + char msg[64]; + + pos = safecat(msg, sizeof msg, pos, "validate: palette size changed: "); + pos = safecatn(msg, sizeof msg, pos, dp->npalette); + pos = safecat(msg, sizeof msg, pos, " -> "); + pos = safecatn(msg, sizeof msg, pos, npalette); + png_error(pp, msg); + } + + { + int i = npalette; /* npalette is aliased */ + + while (--i >= 0) + if (palette[i].red != dp->palette[i].red || + palette[i].green != dp->palette[i].green || + palette[i].blue != dp->palette[i].blue || + palette[i].alpha != dp->palette[i].alpha) + png_error(pp, "validate: PLTE or tRNS chunk changed"); + } +} + +/* By passing a 'standard_display' the progressive callbacks can be used + * directly by the sequential code, the functions suffixed "_imp" are the + * implementations, the functions without the suffix are the callbacks. + * + * The code for the info callback is split into two because this callback calls + * png_read_update_info or png_start_read_image and what gets called depends on + * whether the info needs updating (we want to test both calls in pngvalid.) + */ +static void +standard_info_part1(standard_display *dp, png_structp pp, png_infop pi) +{ + if (png_get_bit_depth(pp, pi) != dp->bit_depth) + png_error(pp, "validate: bit depth changed"); + + if (png_get_color_type(pp, pi) != dp->colour_type) + png_error(pp, "validate: color type changed"); + + if (png_get_filter_type(pp, pi) != PNG_FILTER_TYPE_BASE) + png_error(pp, "validate: filter type changed"); + + if (png_get_interlace_type(pp, pi) != dp->interlace_type) + png_error(pp, "validate: interlacing changed"); + + if (png_get_compression_type(pp, pi) != PNG_COMPRESSION_TYPE_BASE) + png_error(pp, "validate: compression type changed"); + + dp->w = png_get_image_width(pp, pi); + + if (dp->w != standard_width(pp, dp->id)) + png_error(pp, "validate: image width changed"); + + dp->h = png_get_image_height(pp, pi); + + if (dp->h != standard_height(pp, dp->id)) + png_error(pp, "validate: image height changed"); + + /* Record (but don't check at present) the input sBIT according to the colour + * type information. + */ + { + png_color_8p sBIT = 0; + + if (png_get_sBIT(pp, pi, &sBIT) & PNG_INFO_sBIT) + { + int sBIT_invalid = 0; + + if (sBIT == 0) + png_error(pp, "validate: unexpected png_get_sBIT result"); + + if (dp->colour_type & PNG_COLOR_MASK_COLOR) + { + if (sBIT->red == 0 || sBIT->red > dp->bit_depth) + sBIT_invalid = 1; + else + dp->red_sBIT = sBIT->red; + + if (sBIT->green == 0 || sBIT->green > dp->bit_depth) + sBIT_invalid = 1; + else + dp->green_sBIT = sBIT->green; + + if (sBIT->blue == 0 || sBIT->blue > dp->bit_depth) + sBIT_invalid = 1; + else + dp->blue_sBIT = sBIT->blue; + } + + else /* !COLOR */ + { + if (sBIT->gray == 0 || sBIT->gray > dp->bit_depth) + sBIT_invalid = 1; + else + dp->blue_sBIT = dp->green_sBIT = dp->red_sBIT = sBIT->gray; + } + + /* All 8 bits in tRNS for a palette image are significant - see the + * spec. + */ + if (dp->colour_type & PNG_COLOR_MASK_ALPHA) + { + if (sBIT->alpha == 0 || sBIT->alpha > dp->bit_depth) + sBIT_invalid = 1; + else + dp->alpha_sBIT = sBIT->alpha; + } + + if (sBIT_invalid) + png_error(pp, "validate: sBIT value out of range"); + } + } + + /* Important: this is validating the value *before* any transforms have been + * put in place. It doesn't matter for the standard tests, where there are + * no transforms, but it does for other tests where rowbytes may change after + * png_read_update_info. + */ + if (png_get_rowbytes(pp, pi) != standard_rowsize(pp, dp->id)) + png_error(pp, "validate: row size changed"); + + /* Validate the colour type 3 palette (this can be present on other color + * types.) + */ + standard_palette_validate(dp, pp, pi); + + /* In any case always check for a tranparent color (notice that the + * colour type 3 case must not give a successful return on the get_tRNS call + * with these arguments!) + */ + { + png_color_16p trans_color = 0; + + if (png_get_tRNS(pp, pi, 0, 0, &trans_color) & PNG_INFO_tRNS) + { + if (trans_color == 0) + png_error(pp, "validate: unexpected png_get_tRNS (color) result"); + + switch (dp->colour_type) + { + case 0: + dp->transparent.red = dp->transparent.green = dp->transparent.blue = + trans_color->gray; + dp->is_transparent = 1; + break; + + case 2: + dp->transparent.red = trans_color->red; + dp->transparent.green = trans_color->green; + dp->transparent.blue = trans_color->blue; + dp->is_transparent = 1; + break; + + case 3: + /* Not expected because it should result in the array case + * above. + */ + png_error(pp, "validate: unexpected png_get_tRNS result"); + break; + + default: + png_error(pp, "validate: invalid tRNS chunk with alpha image"); + } + } + } + + /* Read the number of passes - expected to match the value used when + * creating the image (interlaced or not). This has the side effect of + * turning on interlace handling (if do_interlace is not set.) + */ + dp->npasses = npasses_from_interlace_type(pp, dp->interlace_type); + if (!dp->do_interlace && dp->npasses != png_set_interlace_handling(pp)) + png_error(pp, "validate: file changed interlace type"); + + /* Caller calls png_read_update_info or png_start_read_image now, then calls + * part2. + */ +} + +/* This must be called *after* the png_read_update_info call to get the correct + * 'rowbytes' value, otherwise png_get_rowbytes will refer to the untransformed + * image. + */ +static void +standard_info_part2(standard_display *dp, png_const_structp pp, + png_const_infop pi, int nImages) +{ + /* Record cbRow now that it can be found. */ + dp->pixel_size = bit_size(pp, png_get_color_type(pp, pi), + png_get_bit_depth(pp, pi)); + dp->bit_width = png_get_image_width(pp, pi) * dp->pixel_size; + dp->cbRow = png_get_rowbytes(pp, pi); + + /* Validate the rowbytes here again. */ + if (dp->cbRow != (dp->bit_width+7)/8) + png_error(pp, "bad png_get_rowbytes calculation"); + + /* Then ensure there is enough space for the output image(s). */ + store_ensure_image(dp->ps, pp, nImages, dp->cbRow, dp->h); +} + +static void +standard_info_imp(standard_display *dp, png_structp pp, png_infop pi, + int nImages) +{ + /* Note that the validation routine has the side effect of turning on + * interlace handling in the subsequent code. + */ + standard_info_part1(dp, pp, pi); + + /* And the info callback has to call this (or png_read_update_info - see + * below in the png_modifier code for that variant. + */ + if (dp->use_update_info) + { + /* For debugging the effect of multiple calls: */ + int i = dp->use_update_info; + while (i-- > 0) + png_read_update_info(pp, pi); + } + + else + png_start_read_image(pp); + + /* Validate the height, width and rowbytes plus ensure that sufficient buffer + * exists for decoding the image. + */ + standard_info_part2(dp, pp, pi, nImages); +} + +static void +standard_info(png_structp pp, png_infop pi) +{ + standard_display *dp = voidcast(standard_display*, + png_get_progressive_ptr(pp)); + + /* Call with nImages==1 because the progressive reader can only produce one + * image. + */ + standard_info_imp(dp, pp, pi, 1 /*only one image*/); +} + +static void +progressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass) +{ + png_const_structp pp = ppIn; + PNG_CONST standard_display *dp = voidcast(standard_display*, + png_get_progressive_ptr(pp)); + + /* When handling interlacing some rows will be absent in each pass, the + * callback still gets called, but with a NULL pointer. This is checked + * in the 'else' clause below. We need our own 'cbRow', but we can't call + * png_get_rowbytes because we got no info structure. + */ + if (new_row != NULL) + { + png_bytep row; + + /* In the case where the reader doesn't do the interlace it gives + * us the y in the sub-image: + */ + if (dp->do_interlace && dp->interlace_type == PNG_INTERLACE_ADAM7) + { +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED + /* Use this opportunity to validate the png 'current' APIs: */ + if (y != png_get_current_row_number(pp)) + png_error(pp, "png_get_current_row_number is broken"); + + if (pass != png_get_current_pass_number(pp)) + png_error(pp, "png_get_current_pass_number is broken"); +#endif + + y = PNG_ROW_FROM_PASS_ROW(y, pass); + } + + /* Validate this just in case. */ + if (y >= dp->h) + png_error(pp, "invalid y to progressive row callback"); + + row = store_image_row(dp->ps, pp, 0, y); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Combine the new row into the old: */ + if (dp->do_interlace) + { + if (dp->interlace_type == PNG_INTERLACE_ADAM7) + deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass); + else + row_copy(row, new_row, dp->pixel_size * dp->w); + } + else + png_progressive_combine_row(pp, row, new_row); +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + } + +#ifdef PNG_READ_INTERLACING_SUPPORTED + else if (dp->interlace_type == PNG_INTERLACE_ADAM7 && + PNG_ROW_IN_INTERLACE_PASS(y, pass) && + PNG_PASS_COLS(dp->w, pass) > 0) + png_error(pp, "missing row in progressive de-interlacing"); +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +} + +static void +sequential_row(standard_display *dp, png_structp pp, png_infop pi, + PNG_CONST int iImage, PNG_CONST int iDisplay) +{ + PNG_CONST int npasses = dp->npasses; + PNG_CONST int do_interlace = dp->do_interlace && + dp->interlace_type == PNG_INTERLACE_ADAM7; + PNG_CONST png_uint_32 height = standard_height(pp, dp->id); + PNG_CONST png_uint_32 width = standard_width(pp, dp->id); + PNG_CONST png_store* ps = dp->ps; + int pass; + + for (pass=0; pass 0 && PNG_ROW_IN_INTERLACE_PASS(y, pass)) + { + /* Read the row into a pair of temporary buffers, then do the + * merge here into the output rows. + */ + png_byte row[STANDARD_ROWMAX], display[STANDARD_ROWMAX]; + + /* The following aids (to some extent) error detection - we can + * see where png_read_row wrote. Use opposite values in row and + * display to make this easier. Don't use 0xff (which is used in + * the image write code to fill unused bits) or 0 (which is a + * likely value to overwrite unused bits with). + */ + memset(row, 0xc5, sizeof row); + memset(display, 0x5c, sizeof display); + + png_read_row(pp, row, display); + + if (iImage >= 0) + deinterlace_row(store_image_row(ps, pp, iImage, y), row, + dp->pixel_size, dp->w, pass); + + if (iDisplay >= 0) + deinterlace_row(store_image_row(ps, pp, iDisplay, y), display, + dp->pixel_size, dp->w, pass); + } + } + else + png_read_row(pp, + iImage >= 0 ? store_image_row(ps, pp, iImage, y) : NULL, + iDisplay >= 0 ? store_image_row(ps, pp, iDisplay, y) : NULL); + } + } + + /* And finish the read operation (only really necessary if the caller wants + * to find additional data in png_info from chunks after the last IDAT.) + */ + png_read_end(pp, pi); +} + +#ifdef PNG_TEXT_SUPPORTED +static void +standard_check_text(png_const_structp pp, png_const_textp tp, + png_const_charp keyword, png_const_charp text) +{ + char msg[1024]; + size_t pos = safecat(msg, sizeof msg, 0, "text: "); + size_t ok; + + pos = safecat(msg, sizeof msg, pos, keyword); + pos = safecat(msg, sizeof msg, pos, ": "); + ok = pos; + + if (tp->compression != TEXT_COMPRESSION) + { + char buf[64]; + + sprintf(buf, "compression [%d->%d], ", TEXT_COMPRESSION, + tp->compression); + pos = safecat(msg, sizeof msg, pos, buf); + } + + if (tp->key == NULL || strcmp(tp->key, keyword) != 0) + { + pos = safecat(msg, sizeof msg, pos, "keyword \""); + if (tp->key != NULL) + { + pos = safecat(msg, sizeof msg, pos, tp->key); + pos = safecat(msg, sizeof msg, pos, "\", "); + } + + else + pos = safecat(msg, sizeof msg, pos, "null, "); + } + + if (tp->text == NULL) + pos = safecat(msg, sizeof msg, pos, "text lost, "); + + else + { + if (tp->text_length != strlen(text)) + { + char buf[64]; + sprintf(buf, "text length changed[%lu->%lu], ", + (unsigned long)strlen(text), (unsigned long)tp->text_length); + pos = safecat(msg, sizeof msg, pos, buf); + } + + if (strcmp(tp->text, text) != 0) + { + pos = safecat(msg, sizeof msg, pos, "text becomes \""); + pos = safecat(msg, sizeof msg, pos, tp->text); + pos = safecat(msg, sizeof msg, pos, "\" (was \""); + pos = safecat(msg, sizeof msg, pos, text); + pos = safecat(msg, sizeof msg, pos, "\"), "); + } + } + + if (tp->itxt_length != 0) + pos = safecat(msg, sizeof msg, pos, "iTXt length set, "); + + if (tp->lang != NULL) + { + pos = safecat(msg, sizeof msg, pos, "iTXt language \""); + pos = safecat(msg, sizeof msg, pos, tp->lang); + pos = safecat(msg, sizeof msg, pos, "\", "); + } + + if (tp->lang_key != NULL) + { + pos = safecat(msg, sizeof msg, pos, "iTXt keyword \""); + pos = safecat(msg, sizeof msg, pos, tp->lang_key); + pos = safecat(msg, sizeof msg, pos, "\", "); + } + + if (pos > ok) + { + msg[pos-2] = '\0'; /* Remove the ", " at the end */ + png_error(pp, msg); + } +} + +static void +standard_text_validate(standard_display *dp, png_const_structp pp, + png_infop pi) +{ + png_textp tp = NULL; + png_uint_32 num_text = png_get_text(pp, pi, &tp, NULL); + + if (num_text == 2 && tp != NULL) + { + standard_check_text(pp, tp, "image name", dp->ps->current->name); + standard_check_text(pp, tp+1, "end marker", "end"); + } + + else + { + char msg[64]; + + sprintf(msg, "expected two text items, got %lu", + (unsigned long)num_text); + png_error(pp, msg); + } +} +#else +# define standard_text_validate(dp,pp,pi) ((void)0) +#endif + +static void +standard_row_validate(standard_display *dp, png_const_structp pp, + int iImage, int iDisplay, png_uint_32 y) +{ + int where; + png_byte std[STANDARD_ROWMAX]; + + /* The row must be pre-initialized to the magic number here for the size + * tests to pass: + */ + memset(std, 178, sizeof std); + standard_row(pp, std, dp->id, y); + + /* At the end both the 'row' and 'display' arrays should end up identical. + * In earlier passes 'row' will be partially filled in, with only the pixels + * that have been read so far, but 'display' will have those pixels + * replicated to fill the unread pixels while reading an interlaced image. +#if PNG_LIBPNG_VER < 10506 + * The side effect inside the libpng sequential reader is that the 'row' + * array retains the correct values for unwritten pixels within the row + * bytes, while the 'display' array gets bits off the end of the image (in + * the last byte) trashed. Unfortunately in the progressive reader the + * row bytes are always trashed, so we always do a pixel_cmp here even though + * a memcmp of all cbRow bytes will succeed for the sequential reader. +#endif + */ + if (iImage >= 0 && + (where = pixel_cmp(std, store_image_row(dp->ps, pp, iImage, y), + dp->bit_width)) != 0) + { + char msg[64]; + sprintf(msg, "PNG image row[%lu][%d] changed from %.2x to %.2x", + (unsigned long)y, where-1, std[where-1], + store_image_row(dp->ps, pp, iImage, y)[where-1]); + png_error(pp, msg); + } + +#if PNG_LIBPNG_VER < 10506 + /* In this case use pixel_cmp because we need to compare a partial + * byte at the end of the row if the row is not an exact multiple + * of 8 bits wide. (This is fixed in libpng-1.5.6 and pixel_cmp is + * changed to match!) + */ +#endif + if (iDisplay >= 0 && + (where = pixel_cmp(std, store_image_row(dp->ps, pp, iDisplay, y), + dp->bit_width)) != 0) + { + char msg[64]; + sprintf(msg, "display row[%lu][%d] changed from %.2x to %.2x", + (unsigned long)y, where-1, std[where-1], + store_image_row(dp->ps, pp, iDisplay, y)[where-1]); + png_error(pp, msg); + } +} + +static void +standard_image_validate(standard_display *dp, png_const_structp pp, int iImage, + int iDisplay) +{ + png_uint_32 y; + + if (iImage >= 0) + store_image_check(dp->ps, pp, iImage); + + if (iDisplay >= 0) + store_image_check(dp->ps, pp, iDisplay); + + for (y=0; yh; ++y) + standard_row_validate(dp, pp, iImage, iDisplay, y); + + /* This avoids false positives if the validation code is never called! */ + dp->ps->validated = 1; +} + +static void +standard_end(png_structp ppIn, png_infop pi) +{ + png_const_structp pp = ppIn; + standard_display *dp = voidcast(standard_display*, + png_get_progressive_ptr(pp)); + + UNUSED(pi) + + /* Validate the image - progressive reading only produces one variant for + * interlaced images. + */ + standard_text_validate(dp, pp, pi); + standard_image_validate(dp, pp, 0, -1); +} + +/* A single test run checking the standard image to ensure it is not damaged. */ +static void +standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id, + int do_interlace, int use_update_info) +{ + standard_display d; + context(psIn, fault); + + /* Set up the display (stack frame) variables from the arguments to the + * function and initialize the locals that are filled in later. + */ + standard_display_init(&d, psIn, id, do_interlace, use_update_info); + + /* Everything is protected by a Try/Catch. The functions called also + * typically have local Try/Catch blocks. + */ + Try + { + png_structp pp; + png_infop pi; + + /* Get a png_struct for reading the image. This will throw an error if it + * fails, so we don't need to check the result. + */ + pp = set_store_for_read(d.ps, &pi, d.id, + d.do_interlace ? (d.ps->progressive ? + "pngvalid progressive deinterlacer" : + "pngvalid sequential deinterlacer") : (d.ps->progressive ? + "progressive reader" : "sequential reader")); + + /* Initialize the palette correctly from the png_store_file. */ + standard_palette_init(&d); + + /* Introduce the correct read function. */ + if (d.ps->progressive) + { + png_set_progressive_read_fn(pp, &d, standard_info, progressive_row, + standard_end); + + /* Now feed data into the reader until we reach the end: */ + store_progressive_read(d.ps, pp, pi); + } + else + { + /* Note that this takes the store, not the display. */ + png_set_read_fn(pp, d.ps, store_read); + + /* Check the header values: */ + png_read_info(pp, pi); + + /* The code tests both versions of the images that the sequential + * reader can produce. + */ + standard_info_imp(&d, pp, pi, 2 /*images*/); + + /* Need the total bytes in the image below; we can't get to this point + * unless the PNG file values have been checked against the expected + * values. + */ + { + sequential_row(&d, pp, pi, 0, 1); + + /* After the last pass loop over the rows again to check that the + * image is correct. + */ + if (!d.speed) + { + standard_text_validate(&d, pp, pi); + standard_image_validate(&d, pp, 0, 1); + } + else + d.ps->validated = 1; + } + } + + /* Check for validation. */ + if (!d.ps->validated) + png_error(pp, "image read failed silently"); + + /* Successful completion. */ + } + + Catch(fault) + d.ps = fault; /* make sure this hasn't been clobbered. */ + + /* In either case clean up the store. */ + store_read_reset(d.ps); +} + +static int +test_standard(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type, + int bdlo, int PNG_CONST bdhi) +{ + for (; bdlo <= bdhi; ++bdlo) + { + int interlace_type; + + for (interlace_type = PNG_INTERLACE_NONE; + interlace_type < PNG_INTERLACE_LAST; ++interlace_type) + { + standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, + interlace_type, 0, 0, 0), 0/*do_interlace*/, pm->use_update_info); + + if (fail(pm)) + return 0; + } + } + + return 1; /* keep going */ +} + +static void +perform_standard_test(png_modifier *pm) +{ + /* Test each colour type over the valid range of bit depths (expressed as + * log2(bit_depth) in turn, stop as soon as any error is detected. + */ + if (!test_standard(pm, 0, 0, READ_BDHI)) + return; + + if (!test_standard(pm, 2, 3, READ_BDHI)) + return; + + if (!test_standard(pm, 3, 0, 3)) + return; + + if (!test_standard(pm, 4, 3, READ_BDHI)) + return; + + if (!test_standard(pm, 6, 3, READ_BDHI)) + return; +} + + +/********************************** SIZE TESTS ********************************/ +static int +test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type, + int bdlo, int PNG_CONST bdhi) +{ + /* Run the tests on each combination. + * + * NOTE: on my 32 bit x86 each of the following blocks takes + * a total of 3.5 seconds if done across every combo of bit depth + * width and height. This is a waste of time in practice, hence the + * hinc and winc stuff: + */ + static PNG_CONST png_byte hinc[] = {1, 3, 11, 1, 5}; + static PNG_CONST png_byte winc[] = {1, 9, 5, 7, 1}; + for (; bdlo <= bdhi; ++bdlo) + { + png_uint_32 h, w; + + for (h=1; h<=16; h+=hinc[bdlo]) for (w=1; w<=16; w+=winc[bdlo]) + { + /* First test all the 'size' images against the sequential + * reader using libpng to deinterlace (where required.) This + * validates the write side of libpng. There are four possibilities + * to validate. + */ + standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, + PNG_INTERLACE_NONE, w, h, 0), 0/*do_interlace*/, + pm->use_update_info); + + if (fail(pm)) + return 0; + + standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, + PNG_INTERLACE_NONE, w, h, 1), 0/*do_interlace*/, + pm->use_update_info); + + if (fail(pm)) + return 0; + + standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, + PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/, + pm->use_update_info); + + if (fail(pm)) + return 0; + + standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, + PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/, + pm->use_update_info); + + if (fail(pm)) + return 0; + + /* Now validate the interlaced read side - do_interlace true, + * in the progressive case this does actually make a difference + * to the code used in the non-interlaced case too. + */ + standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, + PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/, + pm->use_update_info); + + if (fail(pm)) + return 0; + + standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, + PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/, + pm->use_update_info); + + if (fail(pm)) + return 0; + } + } + + return 1; /* keep going */ +} + +static void +perform_size_test(png_modifier *pm) +{ + /* Test each colour type over the valid range of bit depths (expressed as + * log2(bit_depth) in turn, stop as soon as any error is detected. + */ + if (!test_size(pm, 0, 0, READ_BDHI)) + return; + + if (!test_size(pm, 2, 3, READ_BDHI)) + return; + + /* For the moment don't do the palette test - it's a waste of time when + * compared to the grayscale test. + */ +#if 0 + if (!test_size(pm, 3, 0, 3)) + return; +#endif + + if (!test_size(pm, 4, 3, READ_BDHI)) + return; + + if (!test_size(pm, 6, 3, READ_BDHI)) + return; +} + + +/******************************* TRANSFORM TESTS ******************************/ +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* A set of tests to validate libpng image transforms. The possibilities here + * are legion because the transforms can be combined in a combinatorial + * fashion. To deal with this some measure of restraint is required, otherwise + * the tests would take forever. + */ +typedef struct image_pixel +{ + /* A local (pngvalid) representation of a PNG pixel, in all its + * various forms. + */ + unsigned int red, green, blue, alpha; /* For non-palette images. */ + unsigned int palette_index; /* For a palette image. */ + png_byte colour_type; /* As in the spec. */ + png_byte bit_depth; /* Defines bit size in row */ + png_byte sample_depth; /* Scale of samples */ + int have_tRNS; /* tRNS chunk may need processing */ + + /* For checking the code calculates double precision floating point values + * along with an error value, accumulated from the transforms. Because an + * sBIT setting allows larger error bounds (indeed, by the spec, apparently + * up to just less than +/-1 in the scaled value) the *lowest* sBIT for each + * channel is stored. This sBIT value is folded in to the stored error value + * at the end of the application of the transforms to the pixel. + */ + double redf, greenf, bluef, alphaf; + double rede, greene, bluee, alphae; + png_byte red_sBIT, green_sBIT, blue_sBIT, alpha_sBIT; +} image_pixel; + +/* Shared utility function, see below. */ +static void +image_pixel_setf(image_pixel *this, unsigned int max) +{ + this->redf = this->red / (double)max; + this->greenf = this->green / (double)max; + this->bluef = this->blue / (double)max; + this->alphaf = this->alpha / (double)max; + + if (this->red < max) + this->rede = this->redf * DBL_EPSILON; + else + this->rede = 0; + if (this->green < max) + this->greene = this->greenf * DBL_EPSILON; + else + this->greene = 0; + if (this->blue < max) + this->bluee = this->bluef * DBL_EPSILON; + else + this->bluee = 0; + if (this->alpha < max) + this->alphae = this->alphaf * DBL_EPSILON; + else + this->alphae = 0; +} + +/* Initialize the structure for the next pixel - call this before doing any + * transforms and call it for each pixel since all the fields may need to be + * reset. + */ +static void +image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type, + png_byte bit_depth, png_uint_32 x, store_palette palette) +{ + PNG_CONST png_byte sample_depth = (png_byte)(colour_type == + PNG_COLOR_TYPE_PALETTE ? 8 : bit_depth); + PNG_CONST unsigned int max = (1U<palette_index = this->red = this->green = this->blue = + sample(row, colour_type, bit_depth, x, 0); + this->alpha = max; + this->red_sBIT = this->green_sBIT = this->blue_sBIT = this->alpha_sBIT = + sample_depth; + + /* Then override as appropriate: */ + if (colour_type == 3) /* palette */ + { + /* This permits the caller to default to the sample value. */ + if (palette != 0) + { + PNG_CONST unsigned int i = this->palette_index; + + this->red = palette[i].red; + this->green = palette[i].green; + this->blue = palette[i].blue; + this->alpha = palette[i].alpha; + } + } + + else /* not palette */ + { + unsigned int i = 0; + + if (colour_type & 2) + { + this->green = sample(row, colour_type, bit_depth, x, 1); + this->blue = sample(row, colour_type, bit_depth, x, 2); + i = 2; + } + if (colour_type & 4) + this->alpha = sample(row, colour_type, bit_depth, x, ++i); + } + + /* Calculate the scaled values, these are simply the values divided by + * 'max' and the error is initialized to the double precision epsilon value + * from the header file. + */ + image_pixel_setf(this, max); + + /* Store the input information for use in the transforms - these will + * modify the information. + */ + this->colour_type = colour_type; + this->bit_depth = bit_depth; + this->sample_depth = sample_depth; + this->have_tRNS = 0; +} + +/* Convert a palette image to an rgb image. This necessarily converts the tRNS + * chunk at the same time, because the tRNS will be in palette form. The way + * palette validation works means that the original palette is never updated, + * instead the image_pixel value from the row contains the RGB of the + * corresponding palette entry and *this* is updated. Consequently this routine + * only needs to change the colour type information. + */ +static void +image_pixel_convert_PLTE(image_pixel *this) +{ + if (this->colour_type == PNG_COLOR_TYPE_PALETTE) + { + if (this->have_tRNS) + { + this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; + this->have_tRNS = 0; + } + else + this->colour_type = PNG_COLOR_TYPE_RGB; + + /* The bit depth of the row changes at this point too (notice that this is + * the row format, not the sample depth, which is separate.) + */ + this->bit_depth = 8; + } +} + +/* Add an alpha channel; this will import the tRNS information because tRNS is + * not valid in an alpha image. The bit depth will invariably be set to at + * least 8. Palette images will be converted to alpha (using the above API). + */ +static void +image_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display) +{ + if (this->colour_type == PNG_COLOR_TYPE_PALETTE) + image_pixel_convert_PLTE(this); + + if ((this->colour_type & PNG_COLOR_MASK_ALPHA) == 0) + { + if (this->colour_type == PNG_COLOR_TYPE_GRAY) + { + if (this->bit_depth < 8) + this->bit_depth = 8; + + if (this->have_tRNS) + { + this->have_tRNS = 0; + + /* Check the input, original, channel value here against the + * original tRNS gray chunk valie. + */ + if (this->red == display->transparent.red) + this->alphaf = 0; + else + this->alphaf = 1; + } + else + this->alphaf = 1; + + this->colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; + } + + else if (this->colour_type == PNG_COLOR_TYPE_RGB) + { + if (this->have_tRNS) + { + this->have_tRNS = 0; + + /* Again, check the exact input values, not the current transformed + * value! + */ + if (this->red == display->transparent.red && + this->green == display->transparent.green && + this->blue == display->transparent.blue) + this->alphaf = 0; + else + this->alphaf = 1; + + this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; + } + } + + /* The error in the alpha is zero and the sBIT value comes from the + * original sBIT data (actually it will always be the original bit depth). + */ + this->alphae = 0; + this->alpha_sBIT = display->alpha_sBIT; + } +} + +struct transform_display; +typedef struct image_transform +{ + /* The name of this transform: a string. */ + PNG_CONST char *name; + + /* Each transform can be disabled from the command line: */ + int enable; + + /* The global list of transforms; read only. */ + struct image_transform *PNG_CONST list; + + /* The global count of the number of times this transform has been set on an + * image. + */ + unsigned int global_use; + + /* The local count of the number of times this transform has been set. */ + unsigned int local_use; + + /* The next transform in the list, each transform must call its own next + * transform after it has processed the pixel successfully. + */ + PNG_CONST struct image_transform *next; + + /* A single transform for the image, expressed as a series of function + * callbacks and some space for values. + * + * First a callback to add any required modifications to the png_modifier; + * this gets called just before the modifier is set up for read. + */ + void (*ini)(PNG_CONST struct image_transform *this, + struct transform_display *that); + + /* And a callback to set the transform on the current png_read_struct: + */ + void (*set)(PNG_CONST struct image_transform *this, + struct transform_display *that, png_structp pp, png_infop pi); + + /* Then a transform that takes an input pixel in one PNG format or another + * and modifies it by a pngvalid implementation of the transform (thus + * duplicating the libpng intent without, we hope, duplicating the bugs + * in the libpng implementation!) The png_structp is solely to allow error + * reporting via png_error and png_warning. + */ + void (*mod)(PNG_CONST struct image_transform *this, image_pixel *that, + png_const_structp pp, PNG_CONST struct transform_display *display); + + /* Add this transform to the list and return true if the transform is + * meaningful for this colour type and bit depth - if false then the + * transform should have no effect on the image so there's not a lot of + * point running it. + */ + int (*add)(struct image_transform *this, + PNG_CONST struct image_transform **that, png_byte colour_type, + png_byte bit_depth); +} image_transform; + +typedef struct transform_display +{ + standard_display this; + + /* Parameters */ + png_modifier* pm; + PNG_CONST image_transform* transform_list; + + /* Local variables */ + png_byte output_colour_type; + png_byte output_bit_depth; + + /* Modifications (not necessarily used.) */ + gama_modification gama_mod; + chrm_modification chrm_mod; + srgb_modification srgb_mod; +} transform_display; + +/* Set sRGB, cHRM and gAMA transforms as required by the current encoding. */ +static void +transform_set_encoding(transform_display *this) +{ + /* Set up the png_modifier '_current' fields then use these to determine how + * to add appropriate chunks. + */ + png_modifier *pm = this->pm; + + modifier_set_encoding(pm); + + if (modifier_color_encoding_is_set(pm)) + { + if (modifier_color_encoding_is_sRGB(pm)) + srgb_modification_init(&this->srgb_mod, pm, PNG_sRGB_INTENT_ABSOLUTE); + + else + { + /* Set gAMA and cHRM separately. */ + gama_modification_init(&this->gama_mod, pm, pm->current_gamma); + + if (pm->current_encoding != 0) + chrm_modification_init(&this->chrm_mod, pm, pm->current_encoding); + } + } +} + +/* Three functions to end the list: */ +static void +image_transform_ini_end(PNG_CONST image_transform *this, + transform_display *that) +{ + UNUSED(this) + UNUSED(that) +} + +static void +image_transform_set_end(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + UNUSED(this) + UNUSED(that) + UNUSED(pp) + UNUSED(pi) +} + +/* At the end of the list recalculate the output image pixel value from the + * double precision values set up by the preceding 'mod' calls: + */ +static unsigned int +sample_scale(double sample_value, unsigned int scale) +{ + sample_value = floor(sample_value * scale + .5); + + /* Return NaN as 0: */ + if (!(sample_value > 0)) + sample_value = 0; + else if (sample_value > scale) + sample_value = scale; + + return (unsigned int)sample_value; +} + +static void +image_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that, + png_const_structp pp, PNG_CONST transform_display *display) +{ + PNG_CONST unsigned int scale = (1U<sample_depth)-1; + + UNUSED(this) + UNUSED(pp) + UNUSED(display) + + /* At the end recalculate the digitized red green and blue values according + * to the current sample_depth of the pixel. + * + * The sample value is simply scaled to the maximum, checking for over + * and underflow (which can both happen for some image transforms, + * including simple size scaling, though libpng doesn't do that at present. + */ + that->red = sample_scale(that->redf, scale); + + /* The error value is increased, at the end, according to the lowest sBIT + * value seen. Common sense tells us that the intermediate integer + * representations are no more accurate than +/- 0.5 in the integral values, + * the sBIT allows the implementation to be worse than this. In addition the + * PNG specification actually permits any error within the range (-1..+1), + * but that is ignored here. Instead the final digitized value is compared, + * below to the digitized value of the error limits - this has the net effect + * of allowing (almost) +/-1 in the output value. It's difficult to see how + * any algorithm that digitizes intermediate results can be more accurate. + */ + that->rede += 1./(2*((1U<red_sBIT)-1)); + + if (that->colour_type & PNG_COLOR_MASK_COLOR) + { + that->green = sample_scale(that->greenf, scale); + that->blue = sample_scale(that->bluef, scale); + that->greene += 1./(2*((1U<green_sBIT)-1)); + that->bluee += 1./(2*((1U<blue_sBIT)-1)); + } + else + { + that->blue = that->green = that->red; + that->bluef = that->greenf = that->redf; + that->bluee = that->greene = that->rede; + } + + if ((that->colour_type & PNG_COLOR_MASK_ALPHA) || + that->colour_type == PNG_COLOR_TYPE_PALETTE) + { + that->alpha = sample_scale(that->alphaf, scale); + that->alphae += 1./(2*((1U<alpha_sBIT)-1)); + } + else + { + that->alpha = scale; /* opaque */ + that->alpha = 1; /* Override this. */ + that->alphae = 0; /* It's exact ;-) */ + } +} + +/* Static 'end' structure: */ +static image_transform image_transform_end = +{ + "(end)", /* name */ + 1, /* enable */ + 0, /* list */ + 0, /* global_use */ + 0, /* local_use */ + 0, /* next */ + image_transform_ini_end, + image_transform_set_end, + image_transform_mod_end, + 0 /* never called, I want it to crash if it is! */ +}; + +/* Reader callbacks and implementations, where they differ from the standard + * ones. + */ +static void +transform_display_init(transform_display *dp, png_modifier *pm, png_uint_32 id, + PNG_CONST image_transform *transform_list) +{ + memset(dp, 0, sizeof *dp); + + /* Standard fields */ + standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/, + pm->use_update_info); + + /* Parameter fields */ + dp->pm = pm; + dp->transform_list = transform_list; + + /* Local variable fields */ + dp->output_colour_type = 255; /* invalid */ + dp->output_bit_depth = 255; /* invalid */ +} + +static void +transform_info_imp(transform_display *dp, png_structp pp, png_infop pi) +{ + /* Reuse the standard stuff as appropriate. */ + standard_info_part1(&dp->this, pp, pi); + + /* Now set the list of transforms. */ + dp->transform_list->set(dp->transform_list, dp, pp, pi); + + /* Update the info structure for these transforms: */ + { + int i = dp->this.use_update_info; + /* Always do one call, even if use_update_info is 0. */ + do + png_read_update_info(pp, pi); + while (--i > 0); + } + + /* And get the output information into the standard_display */ + standard_info_part2(&dp->this, pp, pi, 1/*images*/); + + /* Plus the extra stuff we need for the transform tests: */ + dp->output_colour_type = png_get_color_type(pp, pi); + dp->output_bit_depth = png_get_bit_depth(pp, pi); + + /* Validate the combination of colour type and bit depth that we are getting + * out of libpng; the semantics of something not in the PNG spec are, at + * best, unclear. + */ + switch (dp->output_colour_type) + { + case PNG_COLOR_TYPE_PALETTE: + if (dp->output_bit_depth > 8) goto error; + /*FALL THROUGH*/ + case PNG_COLOR_TYPE_GRAY: + if (dp->output_bit_depth == 1 || dp->output_bit_depth == 2 || + dp->output_bit_depth == 4) + break; + /*FALL THROUGH*/ + default: + if (dp->output_bit_depth == 8 || dp->output_bit_depth == 16) + break; + /*FALL THROUGH*/ + error: + { + char message[128]; + size_t pos; + + pos = safecat(message, sizeof message, 0, + "invalid final bit depth: colour type("); + pos = safecatn(message, sizeof message, pos, dp->output_colour_type); + pos = safecat(message, sizeof message, pos, ") with bit depth: "); + pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); + + png_error(pp, message); + } + } + + /* Use a test pixel to check that the output agrees with what we expect - + * this avoids running the whole test if the output is unexpected. + */ + { + image_pixel test_pixel; + + memset(&test_pixel, 0, sizeof test_pixel); + test_pixel.colour_type = dp->this.colour_type; /* input */ + test_pixel.bit_depth = dp->this.bit_depth; + if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE) + test_pixel.sample_depth = 8; + else + test_pixel.sample_depth = test_pixel.bit_depth; + /* Don't need sBIT here, but it must be set to non-zero to avoid + * arithmetic overflows. + */ + test_pixel.have_tRNS = dp->this.is_transparent; + test_pixel.red_sBIT = test_pixel.green_sBIT = test_pixel.blue_sBIT = + test_pixel.alpha_sBIT = test_pixel.sample_depth; + + dp->transform_list->mod(dp->transform_list, &test_pixel, pp, dp); + + if (test_pixel.colour_type != dp->output_colour_type) + { + char message[128]; + size_t pos = safecat(message, sizeof message, 0, "colour type "); + + pos = safecatn(message, sizeof message, pos, dp->output_colour_type); + pos = safecat(message, sizeof message, pos, " expected "); + pos = safecatn(message, sizeof message, pos, test_pixel.colour_type); + + png_error(pp, message); + } + + if (test_pixel.bit_depth != dp->output_bit_depth) + { + char message[128]; + size_t pos = safecat(message, sizeof message, 0, "bit depth "); + + pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); + pos = safecat(message, sizeof message, pos, " expected "); + pos = safecatn(message, sizeof message, pos, test_pixel.bit_depth); + + png_error(pp, message); + } + + /* If both bit depth and colour type are correct check the sample depth. + * I believe these are both internal errors. + */ + if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE) + { + if (test_pixel.sample_depth != 8) /* oops - internal error! */ + png_error(pp, "pngvalid: internal: palette sample depth not 8"); + } + else if (test_pixel.sample_depth != dp->output_bit_depth) + { + char message[128]; + size_t pos = safecat(message, sizeof message, 0, + "internal: sample depth "); + + pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); + pos = safecat(message, sizeof message, pos, " expected "); + pos = safecatn(message, sizeof message, pos, test_pixel.sample_depth); + + png_error(pp, message); + } + } +} + +static void +transform_info(png_structp pp, png_infop pi) +{ + transform_info_imp(voidcast(transform_display*, png_get_progressive_ptr(pp)), + pp, pi); +} + +static void +transform_range_check(png_const_structp pp, unsigned int r, unsigned int g, + unsigned int b, unsigned int a, unsigned int in_digitized, double in, + unsigned int out, png_byte sample_depth, double err, double limit, + PNG_CONST char *name, double digitization_error) +{ + /* Compare the scaled, digitzed, values of our local calculation (in+-err) + * with the digitized values libpng produced; 'sample_depth' is the actual + * digitization depth of the libpng output colors (the bit depth except for + * palette images where it is always 8.) The check on 'err' is to detect + * internal errors in pngvalid itself. + */ + unsigned int max = (1U< limit || !(out >= in_min && out <= in_max)) + { + char message[256]; + size_t pos; + + pos = safecat(message, sizeof message, 0, name); + pos = safecat(message, sizeof message, pos, " output value error: rgba("); + pos = safecatn(message, sizeof message, pos, r); + pos = safecat(message, sizeof message, pos, ","); + pos = safecatn(message, sizeof message, pos, g); + pos = safecat(message, sizeof message, pos, ","); + pos = safecatn(message, sizeof message, pos, b); + pos = safecat(message, sizeof message, pos, ","); + pos = safecatn(message, sizeof message, pos, a); + pos = safecat(message, sizeof message, pos, "): "); + pos = safecatn(message, sizeof message, pos, out); + pos = safecat(message, sizeof message, pos, " expected: "); + pos = safecatn(message, sizeof message, pos, in_digitized); + pos = safecat(message, sizeof message, pos, " ("); + pos = safecatd(message, sizeof message, pos, (in-err)*max, 3); + pos = safecat(message, sizeof message, pos, ".."); + pos = safecatd(message, sizeof message, pos, (in+err)*max, 3); + pos = safecat(message, sizeof message, pos, ")"); + + png_error(pp, message); + } +} + +static void +transform_image_validate(transform_display *dp, png_const_structp pp, + png_infop pi) +{ + /* Constants for the loop below: */ + PNG_CONST png_store* PNG_CONST ps = dp->this.ps; + PNG_CONST png_byte in_ct = dp->this.colour_type; + PNG_CONST png_byte in_bd = dp->this.bit_depth; + PNG_CONST png_uint_32 w = dp->this.w; + PNG_CONST png_uint_32 h = dp->this.h; + PNG_CONST png_byte out_ct = dp->output_colour_type; + PNG_CONST png_byte out_bd = dp->output_bit_depth; + PNG_CONST png_byte sample_depth = (png_byte)(out_ct == + PNG_COLOR_TYPE_PALETTE ? 8 : out_bd); + PNG_CONST png_byte red_sBIT = dp->this.red_sBIT; + PNG_CONST png_byte green_sBIT = dp->this.green_sBIT; + PNG_CONST png_byte blue_sBIT = dp->this.blue_sBIT; + PNG_CONST png_byte alpha_sBIT = dp->this.alpha_sBIT; + PNG_CONST int have_tRNS = dp->this.is_transparent; + double digitization_error; + + store_palette out_palette; + png_uint_32 y; + + UNUSED(pi) + + /* Check for row overwrite errors */ + store_image_check(dp->this.ps, pp, 0); + + /* Read the palette corresponding to the output if the output colour type + * indicates a palette, othewise set out_palette to garbage. + */ + if (out_ct == PNG_COLOR_TYPE_PALETTE) + { + /* Validate that the palette count itself has not changed - this is not + * expected. + */ + int npalette = (-1); + + (void)read_palette(out_palette, &npalette, pp, pi); + if (npalette != dp->this.npalette) + png_error(pp, "unexpected change in palette size"); + + digitization_error = .5; + } + else + { + png_byte in_sample_depth; + + memset(out_palette, 0x5e, sizeof out_palette); + + /* assume-8-bit-calculations means assume that if the input has 8 bit + * (or less) samples and the output has 16 bit samples the calculations + * will be done with 8 bit precision, not 16. + * + * TODO: fix this in libpng; png_set_expand_16 should cause 16 bit + * calculations to be used throughout. + */ + if (in_ct == PNG_COLOR_TYPE_PALETTE || in_bd < 16) + in_sample_depth = 8; + else + in_sample_depth = in_bd; + + if (sample_depth != 16 || in_sample_depth > 8 || + !dp->pm->calculations_use_input_precision) + digitization_error = .5; + + /* Else errors are at 8 bit precision, scale .5 in 8 bits to the 16 bits: + */ + else + digitization_error = .5 * 257; + } + + for (y=0; ythis.palette); + + in_pixel.red_sBIT = red_sBIT; + in_pixel.green_sBIT = green_sBIT; + in_pixel.blue_sBIT = blue_sBIT; + in_pixel.alpha_sBIT = alpha_sBIT; + in_pixel.have_tRNS = have_tRNS; + + /* For error detection, below. */ + r = in_pixel.red; + g = in_pixel.green; + b = in_pixel.blue; + a = in_pixel.alpha; + + dp->transform_list->mod(dp->transform_list, &in_pixel, pp, dp); + + /* Read the output pixel and compare it to what we got, we don't + * use the error field here, so no need to update sBIT. + */ + image_pixel_init(&out_pixel, pRow, out_ct, out_bd, x, out_palette); + + /* We don't expect changes to the index here even if the bit depth is + * changed. + */ + if (in_ct == PNG_COLOR_TYPE_PALETTE && + out_ct == PNG_COLOR_TYPE_PALETTE) + { + if (in_pixel.palette_index != out_pixel.palette_index) + png_error(pp, "unexpected transformed palette index"); + } + + /* Check the colours for palette images too - in fact the palette could + * be separately verified itself in most cases. + */ + if (in_pixel.red != out_pixel.red) + transform_range_check(pp, r, g, b, a, in_pixel.red, in_pixel.redf, + out_pixel.red, sample_depth, in_pixel.rede, + dp->pm->limit + 1./(2*((1U<pm->limit + 1./(2*((1U<pm->limit + 1./(2*((1U<pm->limit + 1./(2*((1U<this.ps->validated = 1; +} + +static void +transform_end(png_structp ppIn, png_infop pi) +{ + png_const_structp pp = ppIn; + transform_display *dp = voidcast(transform_display*, + png_get_progressive_ptr(pp)); + + if (!dp->this.speed) + transform_image_validate(dp, pp, pi); + else + dp->this.ps->validated = 1; +} + +/* A single test run. */ +static void +transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn, + PNG_CONST image_transform* transform_listIn, PNG_CONST char * volatile name) +{ + transform_display d; + context(&pmIn->this, fault); + + transform_display_init(&d, pmIn, idIn, transform_listIn); + + Try + { + size_t pos = 0; + png_structp pp; + png_infop pi; + char full_name[256]; + + /* Make sure the encoding fields are correct and enter the required + * modifications. + */ + transform_set_encoding(&d); + + /* Add any modifications required by the transform list. */ + d.transform_list->ini(d.transform_list, &d); + + /* Add the color space information, if any, to the name. */ + pos = safecat(full_name, sizeof full_name, pos, name); + pos = safecat_current_encoding(full_name, sizeof full_name, pos, d.pm); + + /* Get a png_struct for reading the image. */ + pp = set_modifier_for_read(d.pm, &pi, d.this.id, full_name); + standard_palette_init(&d.this); + +# if 0 + /* Logging (debugging only) */ + { + char buffer[256]; + + (void)store_message(&d.pm->this, pp, buffer, sizeof buffer, 0, + "running test"); + + fprintf(stderr, "%s\n", buffer); + } +# endif + + /* Introduce the correct read function. */ + if (d.pm->this.progressive) + { + /* Share the row function with the standard implementation. */ + png_set_progressive_read_fn(pp, &d, transform_info, progressive_row, + transform_end); + + /* Now feed data into the reader until we reach the end: */ + modifier_progressive_read(d.pm, pp, pi); + } + else + { + /* modifier_read expects a png_modifier* */ + png_set_read_fn(pp, d.pm, modifier_read); + + /* Check the header values: */ + png_read_info(pp, pi); + + /* Process the 'info' requirements. Only one image is generated */ + transform_info_imp(&d, pp, pi); + + sequential_row(&d.this, pp, pi, -1, 0); + + if (!d.this.speed) + transform_image_validate(&d, pp, pi); + else + d.this.ps->validated = 1; + } + + modifier_reset(d.pm); + } + + Catch(fault) + { + modifier_reset((png_modifier*)fault); + } +} + +/* The transforms: */ +#define ITSTRUCT(name) image_transform_##name +#define ITDATA(name) image_transform_data_##name +#define image_transform_ini image_transform_default_ini +#define IT(name)\ +static image_transform ITSTRUCT(name) =\ +{\ + #name,\ + 1, /*enable*/\ + &PT, /*list*/\ + 0, /*global_use*/\ + 0, /*local_use*/\ + 0, /*next*/\ + image_transform_ini,\ + image_transform_png_set_##name##_set,\ + image_transform_png_set_##name##_mod,\ + image_transform_png_set_##name##_add\ +} +#define PT ITSTRUCT(end) /* stores the previous transform */ + +/* To save code: */ +static void +image_transform_default_ini(PNG_CONST image_transform *this, + transform_display *that) +{ + this->next->ini(this->next, that); +} + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +static int +image_transform_default_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(colour_type) + UNUSED(bit_depth) + + this->next = *that; + *that = this; + + return 1; +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* png_set_palette_to_rgb */ +static void +image_transform_png_set_palette_to_rgb_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_palette_to_rgb(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_palette_to_rgb_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + if (that->colour_type == PNG_COLOR_TYPE_PALETTE) + image_pixel_convert_PLTE(that); + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_palette_to_rgb_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(bit_depth) + + this->next = *that; + *that = this; + + return colour_type == PNG_COLOR_TYPE_PALETTE; +} + +IT(palette_to_rgb); +#undef PT +#define PT ITSTRUCT(palette_to_rgb) +#endif /* PNG_READ_EXPAND_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* png_set_tRNS_to_alpha */ +static void +image_transform_png_set_tRNS_to_alpha_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_tRNS_to_alpha(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_tRNS_to_alpha_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + /* LIBPNG BUG: this always forces palette images to RGB. */ + if (that->colour_type == PNG_COLOR_TYPE_PALETTE) + image_pixel_convert_PLTE(that); + + /* This effectively does an 'expand' only if there is some transparency to + * convert to an alpha channel. + */ + if (that->have_tRNS) + image_pixel_add_alpha(that, &display->this); + + /* LIBPNG BUG: otherwise libpng still expands to 8 bits! */ + else + { + if (that->bit_depth < 8) + that->bit_depth =8; + if (that->sample_depth < 8) + that->sample_depth = 8; + } + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_tRNS_to_alpha_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(bit_depth) + + this->next = *that; + *that = this; + + /* We don't know yet whether there will be a tRNS chunk, but we know that + * this transformation should do nothing if there already is an alpha + * channel. + */ + return (colour_type & PNG_COLOR_MASK_ALPHA) == 0; +} + +IT(tRNS_to_alpha); +#undef PT +#define PT ITSTRUCT(tRNS_to_alpha) +#endif /* PNG_READ_EXPAND_SUPPORTED */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* png_set_gray_to_rgb */ +static void +image_transform_png_set_gray_to_rgb_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_gray_to_rgb(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_gray_to_rgb_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + /* NOTE: we can actually pend the tRNS processing at this point because we + * can correctly recognize the original pixel value even though we have + * mapped the one gray channel to the three RGB ones, but in fact libpng + * doesn't do this, so we don't either. + */ + if ((that->colour_type & PNG_COLOR_MASK_COLOR) == 0 && that->have_tRNS) + image_pixel_add_alpha(that, &display->this); + + /* Simply expand the bit depth and alter the colour type as required. */ + if (that->colour_type == PNG_COLOR_TYPE_GRAY) + { + /* RGB images have a bit depth at least equal to '8' */ + if (that->bit_depth < 8) + that->sample_depth = that->bit_depth = 8; + + /* And just changing the colour type works here because the green and blue + * channels are being maintained in lock-step with the red/gray: + */ + that->colour_type = PNG_COLOR_TYPE_RGB; + } + + else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) + that->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_gray_to_rgb_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(bit_depth) + + this->next = *that; + *that = this; + + return (colour_type & PNG_COLOR_MASK_COLOR) == 0; +} + +IT(gray_to_rgb); +#undef PT +#define PT ITSTRUCT(gray_to_rgb) +#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* png_set_expand */ +static void +image_transform_png_set_expand_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_expand(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_expand_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + /* The general expand case depends on what the colour type is: */ + if (that->colour_type == PNG_COLOR_TYPE_PALETTE) + image_pixel_convert_PLTE(that); + else if (that->bit_depth < 8) /* grayscale */ + that->sample_depth = that->bit_depth = 8; + + if (that->have_tRNS) + image_pixel_add_alpha(that, &display->this); + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_expand_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(bit_depth) + + this->next = *that; + *that = this; + + /* 'expand' should do nothing for RGBA or GA input - no tRNS and the bit + * depth is at least 8 already. + */ + return (colour_type & PNG_COLOR_MASK_ALPHA) == 0; +} + +IT(expand); +#undef PT +#define PT ITSTRUCT(expand) +#endif /* PNG_READ_EXPAND_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* png_set_expand_gray_1_2_4_to_8 + * LIBPNG BUG: this just does an 'expand' + */ +static void +image_transform_png_set_expand_gray_1_2_4_to_8_set( + PNG_CONST image_transform *this, transform_display *that, png_structp pp, + png_infop pi) +{ + png_set_expand_gray_1_2_4_to_8(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_expand_gray_1_2_4_to_8_mod( + PNG_CONST image_transform *this, image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + image_transform_png_set_expand_mod(this, that, pp, display); +} + +static int +image_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + return image_transform_png_set_expand_add(this, that, colour_type, + bit_depth); +} + +IT(expand_gray_1_2_4_to_8); +#undef PT +#define PT ITSTRUCT(expand_gray_1_2_4_to_8) +#endif /* PNG_READ_EXPAND_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* png_set_expand_16 */ +static void +image_transform_png_set_expand_16_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_expand_16(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + /* Expect expand_16 to expand everything to 16 bits as a result of also + * causing 'expand' to happen. + */ + if (that->colour_type == PNG_COLOR_TYPE_PALETTE) + image_pixel_convert_PLTE(that); + + if (that->have_tRNS) + image_pixel_add_alpha(that, &display->this); + + if (that->bit_depth < 16) + that->sample_depth = that->bit_depth = 16; + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_expand_16_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(colour_type) + + this->next = *that; + *that = this; + + /* expand_16 does something unless the bit depth is already 16. */ + return bit_depth < 16; +} + +IT(expand_16); +#undef PT +#define PT ITSTRUCT(expand_16) +#endif /* PNG_READ_EXPAND_16_SUPPORTED */ + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* API added in 1.5.4 */ +/* png_set_scale_16 */ +static void +image_transform_png_set_scale_16_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_scale_16(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_scale_16_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + if (that->bit_depth == 16) + { + that->sample_depth = that->bit_depth = 8; + if (that->red_sBIT > 8) that->red_sBIT = 8; + if (that->green_sBIT > 8) that->green_sBIT = 8; + if (that->blue_sBIT > 8) that->blue_sBIT = 8; + if (that->alpha_sBIT > 8) that->alpha_sBIT = 8; + } + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_scale_16_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(colour_type) + + this->next = *that; + *that = this; + + return bit_depth > 8; +} + +IT(scale_16); +#undef PT +#define PT ITSTRUCT(scale_16) +#endif /* PNG_READ_SCALE_16_TO_8_SUPPORTED (1.5.4 on) */ + +#ifdef PNG_READ_16_TO_8_SUPPORTED /* the default before 1.5.4 */ +/* png_set_strip_16 */ +static void +image_transform_png_set_strip_16_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_strip_16(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + if (that->bit_depth == 16) + { + that->sample_depth = that->bit_depth = 8; + if (that->red_sBIT > 8) that->red_sBIT = 8; + if (that->green_sBIT > 8) that->green_sBIT = 8; + if (that->blue_sBIT > 8) that->blue_sBIT = 8; + if (that->alpha_sBIT > 8) that->alpha_sBIT = 8; + + /* Prior to 1.5.4 png_set_strip_16 would use an 'accurate' method if this + * configuration option is set. From 1.5.4 the flag is never set and the + * 'scale' API (above) must be used. + */ +# ifdef PNG_READ_ACCURATE_SCALE_SUPPORTED +# if PNG_LIBPNG_VER >= 10504 +# error PNG_READ_ACCURATE_SCALE should not be set +# endif + + /* The strip 16 algorithm drops the low 8 bits rather than calculating + * 1/257, so we need to adjust the permitted errors appropriately: + * Notice that this is only relevant prior to the addition of the + * png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!) + */ + { + PNG_CONST double d = (255-128.5)/65535; + that->rede += d; + that->greene += d; + that->bluee += d; + that->alphae += d; + } +# endif + } + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_strip_16_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(colour_type) + + this->next = *that; + *that = this; + + return bit_depth > 8; +} + +IT(strip_16); +#undef PT +#define PT ITSTRUCT(strip_16) +#endif /* PNG_READ_16_TO_8_SUPPORTED */ + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +/* png_set_strip_alpha */ +static void +image_transform_png_set_strip_alpha_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_strip_alpha(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_strip_alpha_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) + that->colour_type = PNG_COLOR_TYPE_GRAY; + else if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) + that->colour_type = PNG_COLOR_TYPE_RGB; + + that->have_tRNS = 0; + that->alphaf = 1; + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_strip_alpha_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(bit_depth) + + this->next = *that; + *that = this; + + return (colour_type & PNG_COLOR_MASK_ALPHA) != 0; +} + +IT(strip_alpha); +#undef PT +#define PT ITSTRUCT(strip_alpha) +#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* png_set_rgb_to_gray(png_structp, int err_action, double red, double green) + * png_set_rgb_to_gray_fixed(png_structp, int err_action, png_fixed_point red, + * png_fixed_point green) + * png_get_rgb_to_gray_status + * + * The 'default' test here uses values known to be used inside libpng: + * + * red: 6968 + * green: 23434 + * blue: 2366 + * + * These values are being retained for compatibility, along with the somewhat + * broken truncation calculation in the fast-and-inaccurate code path. Older + * versions of libpng will fail the accuracy tests below because they use the + * truncation algorithm everywhere. + */ +#define data ITDATA(rgb_to_gray) +static struct +{ + double gamma; /* File gamma to use in processing */ + + /* The following are the parameters for png_set_rgb_to_gray: */ +# ifdef PNG_FLOATING_POINT_SUPPORTED + double red_to_set; + double green_to_set; +# else + png_fixed_point red_to_set; + png_fixed_point green_to_set; +# endif + + /* The actual coefficients: */ + double red_coefficient; + double green_coefficient; + double blue_coefficient; + + /* Set if the coeefficients have been overridden. */ + int coefficients_overridden; +} data; + +#undef image_transform_ini +#define image_transform_ini image_transform_png_set_rgb_to_gray_ini +static void +image_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this, + transform_display *that) +{ + png_modifier *pm = that->pm; + PNG_CONST color_encoding *e = pm->current_encoding; + + UNUSED(this) + + /* Since we check the encoding this flag must be set: */ + pm->test_uses_encoding = 1; + + /* If 'e' is not NULL chromaticity information is present and either a cHRM + * or an sRGB chunk will be inserted. + */ + if (e != 0) + { + /* Coefficients come from the encoding, but may need to be normalized to a + * white point Y of 1.0 + */ + PNG_CONST double whiteY = e->red.Y + e->green.Y + e->blue.Y; + + data.red_coefficient = e->red.Y; + data.green_coefficient = e->green.Y; + data.blue_coefficient = e->blue.Y; + + if (whiteY != 1) + { + data.red_coefficient /= whiteY; + data.green_coefficient /= whiteY; + data.blue_coefficient /= whiteY; + } + } + + else + { + /* The default (built in) coeffcients, as above: */ + data.red_coefficient = 6968 / 32768.; + data.green_coefficient = 23434 / 32768.; + data.blue_coefficient = 2366 / 32768.; + } + + data.gamma = pm->current_gamma; + + /* If not set then the calculations assume linear encoding (implicitly): */ + if (data.gamma == 0) + data.gamma = 1; + + /* The arguments to png_set_rgb_to_gray can override the coefficients implied + * by the color space encoding. If doing exhaustive checks do the override + * in each case, otherwise do it randomly. + */ + if (pm->test_exhaustive) + { + /* First time in coefficients_overridden is 0, the following sets it to 1, + * so repeat if it is set. If a test fails this may mean we subsequently + * skip a non-override test, ignore that. + */ + data.coefficients_overridden = !data.coefficients_overridden; + pm->repeat = data.coefficients_overridden != 0; + } + + else + data.coefficients_overridden = random_choice(); + + if (data.coefficients_overridden) + { + /* These values override the color encoding defaults, simply use random + * numbers. + */ + png_uint_32 ru; + double total; + + RANDOMIZE(ru); + data.green_coefficient = total = (ru & 0xffff) / 65535.; + ru >>= 16; + data.red_coefficient = (1 - total) * (ru & 0xffff) / 65535.; + total += data.red_coefficient; + data.blue_coefficient = 1 - total; + +# ifdef PNG_FLOATING_POINT_SUPPORTED + data.red_to_set = data.red_coefficient; + data.green_to_set = data.green_coefficient; +# else + data.red_to_set = fix(data.red_coefficient); + data.green_to_set = fix(data.green_coefficient); +# endif + + /* The following just changes the error messages: */ + pm->encoding_ignored = 1; + } + + else + { + data.red_to_set = -1; + data.green_to_set = -1; + } + + /* Adjust the error limit in the png_modifier because of the larger errors + * produced in the digitization during the gamma handling. + */ + if (data.gamma != 1) /* Use gamma tables */ + { + if (that->this.bit_depth == 16 || pm->assume_16_bit_calculations) + { + /* The 16 bit case ends up producing a maximum error of about + * +/-5 in 65535, allow for +/-8 with the given gamma. + */ + that->pm->limit += pow(8./65535, data.gamma); + } + + else + { + /* Rounding to 8 bits in the linear space causes massive errors which + * will trigger the error check in transform_range_check. Fix that + * here by taking the gamma encoding into account. + */ + that->pm->limit += pow(1./255, data.gamma); + } + } + + else + { + /* With no gamma correction a large error comes from the truncation of the + * calculation in the 8 bit case, allow for that here. + */ + if (that->this.bit_depth != 16) + that->pm->limit += 4E-3; + } +} + +static void +image_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + PNG_CONST int error_action = 1; /* no error, no defines in png.h */ + +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_rgb_to_gray(pp, error_action, data.red_to_set, data.green_to_set); +# else + png_set_rgb_to_gray_fixed(pp, error_action, data.red_to_set, + data.green_to_set); +# endif + +# ifdef PNG_READ_cHRM_SUPPORTED + if (that->pm->current_encoding != 0) + { + /* We have an encoding so a cHRM chunk may have been set; if so then + * check that the libpng APIs give the correct (X,Y,Z) values within + * some margin of error for the round trip through the chromaticity + * form. + */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define API_function png_get_cHRM_XYZ +# define API_form "FP" +# define API_type double +# define API_cvt(x) (x) +# else +# define API_function png_get_cHRM_XYZ_fixed +# define API_form "fixed" +# define API_type png_fixed_point +# define API_cvt(x) ((double)(x)/PNG_FP_1) +# endif + + API_type rX, gX, bX; + API_type rY, gY, bY; + API_type rZ, gZ, bZ; + + if ((API_function(pp, pi, &rX, &rY, &rZ, &gX, &gY, &gZ, &bX, &bY, &bZ) + & PNG_INFO_cHRM) != 0) + { + double maxe; + PNG_CONST char *el; + color_encoding e, o; + + /* Expect libpng to return a normalized result, but the original + * color space encoding may not be normalized. + */ + modifier_current_encoding(that->pm, &o); + normalize_color_encoding(&o); + + /* Sanity check the pngvalid code - the coefficients should match + * the normalized Y values of the encoding unless they were + * overridden. + */ + if (data.red_to_set == -1 && data.green_to_set == -1 && + (fabs(o.red.Y - data.red_coefficient) > DBL_EPSILON || + fabs(o.green.Y - data.green_coefficient) > DBL_EPSILON || + fabs(o.blue.Y - data.blue_coefficient) > DBL_EPSILON)) + png_error(pp, "internal pngvalid cHRM coefficient error"); + + /* Generate a colour space encoding. */ + e.gamma = o.gamma; /* not used */ + e.red.X = API_cvt(rX); + e.red.Y = API_cvt(rY); + e.red.Z = API_cvt(rZ); + e.green.X = API_cvt(gX); + e.green.Y = API_cvt(gY); + e.green.Z = API_cvt(gZ); + e.blue.X = API_cvt(bX); + e.blue.Y = API_cvt(bY); + e.blue.Z = API_cvt(bZ); + + /* This should match the original one from the png_modifier, within + * the range permitted by the libpng fixed point representation. + */ + maxe = 0; + el = "-"; /* Set to element name with error */ + +# define CHECK(col,x)\ + {\ + double err = fabs(o.col.x - e.col.x);\ + if (err > maxe)\ + {\ + maxe = err;\ + el = #col "(" #x ")";\ + }\ + } + + CHECK(red,X) + CHECK(red,Y) + CHECK(red,Z) + CHECK(green,X) + CHECK(green,Y) + CHECK(green,Z) + CHECK(blue,X) + CHECK(blue,Y) + CHECK(blue,Z) + + /* Here in both fixed and floating cases to check the values read + * from the cHRm chunk. PNG uses fixed point in the cHRM chunk, so + * we can't expect better than +/-.5E-5 on the result, allow 1E-5. + */ + if (maxe >= 1E-5) + { + size_t pos = 0; + char buffer[256]; + + pos = safecat(buffer, sizeof buffer, pos, API_form); + pos = safecat(buffer, sizeof buffer, pos, " cHRM "); + pos = safecat(buffer, sizeof buffer, pos, el); + pos = safecat(buffer, sizeof buffer, pos, " error: "); + pos = safecatd(buffer, sizeof buffer, pos, maxe, 7); + pos = safecat(buffer, sizeof buffer, pos, " "); + /* Print the color space without the gamma value: */ + pos = safecat_color_encoding(buffer, sizeof buffer, pos, &o, 0); + pos = safecat(buffer, sizeof buffer, pos, " -> "); + pos = safecat_color_encoding(buffer, sizeof buffer, pos, &e, 0); + + png_error(pp, buffer); + } + } + } +# endif /* READ_cHRM */ + + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + if ((that->colour_type & PNG_COLOR_MASK_COLOR) != 0) + { + double gray, err; + + if (that->colour_type == PNG_COLOR_TYPE_PALETTE) + image_pixel_convert_PLTE(that); + + /* Image now has RGB channels... */ + { + PNG_CONST png_modifier *pm = display->pm; + PNG_CONST unsigned int sample_depth = that->sample_depth; + int isgray; + double r, g, b; + double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi; + + /* Do this using interval arithmetic, otherwise it is too difficult to + * handle the errors correctly. + * + * To handle the gamma correction work out the upper and lower bounds + * of the digitized value. Assume rounding here - normally the values + * will be identical after this operation if there is only one + * transform, feel free to delete the png_error checks on this below in + * the future (this is just me trying to ensure it works!) + */ + r = rlo = rhi = that->redf; + rlo -= that->rede; + rlo = digitize(pm, rlo, sample_depth, 1/*round*/); + rhi += that->rede; + rhi = digitize(pm, rhi, sample_depth, 1/*round*/); + + g = glo = ghi = that->greenf; + glo -= that->greene; + glo = digitize(pm, glo, sample_depth, 1/*round*/); + ghi += that->greene; + ghi = digitize(pm, ghi, sample_depth, 1/*round*/); + + b = blo = bhi = that->bluef; + blo -= that->bluee; + blo = digitize(pm, blo, sample_depth, 1/*round*/); + bhi += that->greene; + bhi = digitize(pm, bhi, sample_depth, 1/*round*/); + + isgray = r==g && g==b; + + if (data.gamma != 1) + { + PNG_CONST double power = 1/data.gamma; + PNG_CONST double abse = abserr(pm, sample_depth, sample_depth); + + /* 'abse' is the absolute error permitted in linear calculations. It + * is used here to capture the error permitted in the handling + * (undoing) of the gamma encoding. Once again digitization occurs + * to handle the upper and lower bounds of the values. This is + * where the real errors are introduced. + */ + r = pow(r, power); + rlo = digitize(pm, pow(rlo, power)-abse, sample_depth, 1); + rhi = digitize(pm, pow(rhi, power)+abse, sample_depth, 1); + + g = pow(g, power); + glo = digitize(pm, pow(glo, power)-abse, sample_depth, 1); + ghi = digitize(pm, pow(ghi, power)+abse, sample_depth, 1); + + b = pow(b, power); + blo = digitize(pm, pow(blo, power)-abse, sample_depth, 1); + bhi = digitize(pm, pow(bhi, power)+abse, sample_depth, 1); + } + + /* Now calculate the actual gray values. Although the error in the + * coefficients depends on whether they were specified on the command + * line (in which case truncation to 15 bits happened) or not (rounding + * was used) the maxium error in an individual coefficient is always + * 1/32768, because even in the rounding case the requirement that + * coefficients add up to 32768 can cause a larger rounding error. + * + * The only time when rounding doesn't occur in 1.5.5 and later is when + * the non-gamma code path is used for less than 16 bit data. + */ + gray = r * data.red_coefficient + g * data.green_coefficient + + b * data.blue_coefficient; + + { + PNG_CONST int do_round = data.gamma != 1 || sample_depth == 16; + PNG_CONST double ce = 1. / 32768; + + graylo = digitize(pm, rlo * (data.red_coefficient-ce) + + glo * (data.green_coefficient-ce) + + blo * (data.blue_coefficient-ce), sample_depth, do_round); + if (graylo <= 0) + graylo = 0; + + grayhi = digitize(pm, rhi * (data.red_coefficient+ce) + + ghi * (data.green_coefficient+ce) + + bhi * (data.blue_coefficient+ce), sample_depth, do_round); + if (grayhi >= 1) + grayhi = 1; + } + + /* And invert the gamma. */ + if (data.gamma != 1) + { + PNG_CONST double power = data.gamma; + + gray = pow(gray, power); + graylo = digitize(pm, pow(graylo, power), sample_depth, 1); + grayhi = digitize(pm, pow(grayhi, power), sample_depth, 1); + } + + /* Now the error can be calculated. + * + * If r==g==b because there is no overall gamma correction libpng + * currently preserves the original value. + */ + if (isgray) + err = (that->rede + that->greene + that->bluee)/3; + + else + { + err = fabs(grayhi-gray); + if (fabs(gray - graylo) > err) + err = fabs(graylo-gray); + + /* Check that this worked: */ + if (err > display->pm->limit) + { + size_t pos = 0; + char buffer[128]; + + pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error "); + pos = safecatd(buffer, sizeof buffer, pos, err, 6); + pos = safecat(buffer, sizeof buffer, pos, " exceeds limit "); + pos = safecatd(buffer, sizeof buffer, pos, + display->pm->limit, 6); + png_error(pp, buffer); + } + } + } + + that->bluef = that->greenf = that->redf = gray; + that->bluee = that->greene = that->rede = err; + + /* The sBIT is the minium of the three colour channel sBITs. */ + if (that->red_sBIT > that->green_sBIT) + that->red_sBIT = that->green_sBIT; + if (that->red_sBIT > that->blue_sBIT) + that->red_sBIT = that->blue_sBIT; + that->blue_sBIT = that->green_sBIT = that->red_sBIT; + + /* And remove the colour bit in the type: */ + if (that->colour_type == PNG_COLOR_TYPE_RGB) + that->colour_type = PNG_COLOR_TYPE_GRAY; + else if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) + that->colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; + } + + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_rgb_to_gray_add(image_transform *this, + PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) +{ + UNUSED(bit_depth) + + this->next = *that; + *that = this; + + return (colour_type & PNG_COLOR_MASK_COLOR) != 0; +} + +#undef data +IT(rgb_to_gray); +#undef PT +#define PT ITSTRUCT(rgb_to_gray) +#undef image_transform_ini +#define image_transform_ini image_transform_default_ini +#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */ + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* png_set_background(png_structp, png_const_color_16p background_color, + * int background_gamma_code, int need_expand, double background_gamma) + * png_set_background_fixed(png_structp, png_const_color_16p background_color, + * int background_gamma_code, int need_expand, + * png_fixed_point background_gamma) + * + * As with rgb_to_gray this ignores the gamma (at present.) +*/ +#define data ITDATA(background) +static image_pixel data; + +static void +image_transform_png_set_background_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_byte colour_type, bit_depth; + png_byte random_bytes[8]; /* 8 bytes - 64 bits - the biggest pixel */ + png_color_16 back; + + /* We need a background colour, because we don't know exactly what transforms + * have been set we have to supply the colour in the original file format and + * so we need to know what that is! The background colour is stored in the + * transform_display. + */ + RANDOMIZE(random_bytes); + + /* Read the random value, for colour type 3 the background colour is actually + * expressed as a 24bit rgb, not an index. + */ + colour_type = that->this.colour_type; + if (colour_type == 3) + { + colour_type = PNG_COLOR_TYPE_RGB; + bit_depth = 8; + } + + else + bit_depth = that->this.bit_depth; + + image_pixel_init(&data, random_bytes, colour_type, + bit_depth, 0/*x*/, 0/*unused: palette*/); + + /* Extract the background colour from this image_pixel, but make sure the + * unused fields of 'back' are garbage. + */ + RANDOMIZE(back); + + if (colour_type & PNG_COLOR_MASK_COLOR) + { + back.red = (png_uint_16)data.red; + back.green = (png_uint_16)data.green; + back.blue = (png_uint_16)data.blue; + } + + else + back.gray = (png_uint_16)data.red; + +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, 1/*need expand*/, + 0); +# else + png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, + 1/*need expand*/, 0); +# endif + + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_background_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + /* Check for tRNS first: */ + if (that->have_tRNS && that->colour_type != PNG_COLOR_TYPE_PALETTE) + image_pixel_add_alpha(that, &display->this); + + /* This is only necessary if the alpha value is less than 1. */ + if (that->alphaf < 1) + { + /* Now we do the background calculation without any gamma correction. */ + if (that->alphaf <= 0) + { + that->redf = data.redf; + that->greenf = data.greenf; + that->bluef = data.bluef; + + that->rede = data.rede; + that->greene = data.greene; + that->bluee = data.bluee; + + that->red_sBIT= data.red_sBIT; + that->green_sBIT= data.green_sBIT; + that->blue_sBIT= data.blue_sBIT; + } + + else /* 0 < alpha < 1 */ + { + double alf = 1 - that->alphaf; + + that->redf = that->redf * that->alphaf + data.redf * alf; + that->rede = that->rede * that->alphaf + data.rede * alf + + DBL_EPSILON; + that->greenf = that->greenf * that->alphaf + data.greenf * alf; + that->greene = that->greene * that->alphaf + data.greene * alf + + DBL_EPSILON; + that->bluef = that->bluef * that->alphaf + data.bluef * alf; + that->bluee = that->bluee * that->alphaf + data.bluee * alf + + DBL_EPSILON; + } + + /* Remove the alpha type and set the alpha (not in that order.) */ + that->alphaf = 1; + that->alphae = 0; + + if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) + that->colour_type = PNG_COLOR_TYPE_RGB; + else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) + that->colour_type = PNG_COLOR_TYPE_GRAY; + /* PNG_COLOR_TYPE_PALETTE is not changed */ + } + + this->next->mod(this->next, that, pp, display); +} + +#define image_transform_png_set_background_add image_transform_default_add + +#undef data +IT(background); +#undef PT +#define PT ITSTRUCT(background) +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + +/* This may just be 'end' if all the transforms are disabled! */ +static image_transform *PNG_CONST image_transform_first = &PT; + +static void +transform_enable(PNG_CONST char *name) +{ + /* Everything starts out enabled, so if we see an 'enable' disabled + * everything else the first time round. + */ + static int all_disabled = 0; + int found_it = 0; + image_transform *list = image_transform_first; + + while (list != &image_transform_end) + { + if (strcmp(list->name, name) == 0) + { + list->enable = 1; + found_it = 1; + } + else if (!all_disabled) + list->enable = 0; + + list = list->list; + } + + all_disabled = 1; + + if (!found_it) + { + fprintf(stderr, "pngvalid: --transform-enable=%s: unknown transform\n", + name); + exit(1); + } +} + +static void +transform_disable(PNG_CONST char *name) +{ + image_transform *list = image_transform_first; + + while (list != &image_transform_end) + { + if (strcmp(list->name, name) == 0) + { + list->enable = 0; + return; + } + + list = list->list; + } + + fprintf(stderr, "pngvalid: --transform-disable=%s: unknown transform\n", + name); + exit(1); +} + +static void +image_transform_reset_count(void) +{ + image_transform *next = image_transform_first; + int count = 0; + + while (next != &image_transform_end) + { + next->local_use = 0; + next->next = 0; + next = next->list; + ++count; + } + + /* This can only happen if we every have more than 32 transforms (excluding + * the end) in the list. + */ + if (count > 32) abort(); +} + +static int +image_transform_test_counter(png_uint_32 counter, unsigned int max) +{ + /* Test the list to see if there is any point contining, given a current + * counter and a 'max' value. + */ + image_transform *next = image_transform_first; + + while (next != &image_transform_end) + { + /* For max 0 or 1 continue until the counter overflows: */ + counter >>= 1; + + /* Continue if any entry hasn't reacked the max. */ + if (max > 1 && next->local_use < max) + return 1; + next = next->list; + } + + return max <= 1 && counter == 0; +} + +static png_uint_32 +image_transform_add(PNG_CONST image_transform **this, unsigned int max, + png_uint_32 counter, char *name, size_t sizeof_name, size_t *pos, + png_byte colour_type, png_byte bit_depth) +{ + for (;;) /* until we manage to add something */ + { + png_uint_32 mask; + image_transform *list; + + /* Find the next counter value, if the counter is zero this is the start + * of the list. This routine always returns the current counter (not the + * next) so it returns 0 at the end and expects 0 at the beginning. + */ + if (counter == 0) /* first time */ + { + image_transform_reset_count(); + if (max <= 1) + counter = 1; + else + counter = random_32(); + } + else /* advance the counter */ + { + switch (max) + { + case 0: ++counter; break; + case 1: counter <<= 1; break; + default: counter = random_32(); break; + } + } + + /* Now add all these items, if possible */ + *this = &image_transform_end; + list = image_transform_first; + mask = 1; + + /* Go through the whole list adding anything that the counter selects: */ + while (list != &image_transform_end) + { + if ((counter & mask) != 0 && list->enable && + (max == 0 || list->local_use < max)) + { + /* Candidate to add: */ + if (list->add(list, this, colour_type, bit_depth) || max == 0) + { + /* Added, so add to the name too. */ + *pos = safecat(name, sizeof_name, *pos, " +"); + *pos = safecat(name, sizeof_name, *pos, list->name); + } + + else + { + /* Not useful and max>0, so remove it from *this: */ + *this = list->next; + list->next = 0; + + /* And, since we know it isn't useful, stop it being added again + * in this run: + */ + list->local_use = max; + } + } + + mask <<= 1; + list = list->list; + } + + /* Now if anything was added we have something to do. */ + if (*this != &image_transform_end) + return counter; + + /* Nothing added, but was there anything in there to add? */ + if (!image_transform_test_counter(counter, max)) + return 0; + } +} + +#ifdef THIS_IS_THE_PROFORMA +static void +image_transform_png_set_@_set(PNG_CONST image_transform *this, + transform_display *that, png_structp pp, png_infop pi) +{ + png_set_@(pp); + this->next->set(this->next, that, pp, pi); +} + +static void +image_transform_png_set_@_mod(PNG_CONST image_transform *this, + image_pixel *that, png_const_structp pp, + PNG_CONST transform_display *display) +{ + this->next->mod(this->next, that, pp, display); +} + +static int +image_transform_png_set_@_add(image_transform *this, + PNG_CONST image_transform **that, char *name, size_t sizeof_name, + size_t *pos, png_byte colour_type, png_byte bit_depth) +{ + this->next = *that; + *that = this; + + *pos = safecat(name, sizeof_name, *pos, " +@"); + + return 1; +} + +IT(@); +#endif + +/* png_set_quantize(png_structp, png_colorp palette, int num_palette, + * int maximum_colors, png_const_uint_16p histogram, int full_quantize) + * + * Very difficult to validate this! + */ +/*NOTE: TBD NYI */ + +/* The data layout transforms are handled by swapping our own channel data, + * necessarily these need to happen at the end of the transform list because the + * semantic of the channels changes after these are executed. Some of these, + * like set_shift and set_packing, can't be done at present because they change + * the layout of the data at the sub-sample level so sample() won't get the + * right answer. + */ +/* png_set_invert_alpha */ +/*NOTE: TBD NYI */ + +/* png_set_bgr */ +/*NOTE: TBD NYI */ + +/* png_set_swap_alpha */ +/*NOTE: TBD NYI */ + +/* png_set_swap */ +/*NOTE: TBD NYI */ + +/* png_set_filler, (png_structp png_ptr, png_uint_32 filler, int flags)); */ +/*NOTE: TBD NYI */ + +/* png_set_add_alpha, (png_structp png_ptr, png_uint_32 filler, int flags)); */ +/*NOTE: TBD NYI */ + +/* png_set_packing */ +/*NOTE: TBD NYI */ + +/* png_set_packswap */ +/*NOTE: TBD NYI */ + +/* png_set_invert_mono */ +/*NOTE: TBD NYI */ + +/* png_set_shift(png_structp, png_const_color_8p true_bits) */ +/*NOTE: TBD NYI */ + +static void +perform_transform_test(png_modifier *pm) +{ + png_byte colour_type = 0; + png_byte bit_depth = 0; + unsigned int palette_number = 0; + + while (next_format(&colour_type, &bit_depth, &palette_number)) + { + png_uint_32 counter = 0; + size_t base_pos; + char name[64]; + + base_pos = safecat(name, sizeof name, 0, "transform:"); + + for (;;) + { + size_t pos = base_pos; + PNG_CONST image_transform *list = 0; + + /* 'max' is currently hardwired to '1'; this should be settable on the + * command line. + */ + counter = image_transform_add(&list, 1/*max*/, counter, + name, sizeof name, &pos, colour_type, bit_depth); + + if (counter == 0) + break; + + /* The command line can change this to checking interlaced images. */ + do + { + pm->repeat = 0; + transform_test(pm, FILEID(colour_type, bit_depth, palette_number, + pm->interlace_type, 0, 0, 0), list, name); + + if (fail(pm)) + return; + } + while (pm->repeat); + } + } +} +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +/********************************* GAMMA TESTS ********************************/ +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Reader callbacks and implementations, where they differ from the standard + * ones. + */ +typedef struct gamma_display +{ + standard_display this; + + /* Parameters */ + png_modifier* pm; + double file_gamma; + double screen_gamma; + double background_gamma; + png_byte sbit; + int threshold_test; + int use_input_precision; + int scale16; + int expand16; + int do_background; + png_color_16 background_color; + + /* Local variables */ + double maxerrout; + double maxerrpc; + double maxerrabs; +} gamma_display; + +#define ALPHA_MODE_OFFSET 4 + +static void +gamma_display_init(gamma_display *dp, png_modifier *pm, png_uint_32 id, + double file_gamma, double screen_gamma, png_byte sbit, int threshold_test, + int use_input_precision, int scale16, int expand16, + int do_background, PNG_CONST png_color_16 *pointer_to_the_background_color, + double background_gamma) +{ + /* Standard fields */ + standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/, + pm->use_update_info); + + /* Parameter fields */ + dp->pm = pm; + dp->file_gamma = file_gamma; + dp->screen_gamma = screen_gamma; + dp->background_gamma = background_gamma; + dp->sbit = sbit; + dp->threshold_test = threshold_test; + dp->use_input_precision = use_input_precision; + dp->scale16 = scale16; + dp->expand16 = expand16; + dp->do_background = do_background; + if (do_background && pointer_to_the_background_color != 0) + dp->background_color = *pointer_to_the_background_color; + else + memset(&dp->background_color, 0, sizeof dp->background_color); + + /* Local variable fields */ + dp->maxerrout = dp->maxerrpc = dp->maxerrabs = 0; +} + +static void +gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi) +{ + /* Reuse the standard stuff as appropriate. */ + standard_info_part1(&dp->this, pp, pi); + + /* If requested strip 16 to 8 bits - this is handled automagically below + * because the output bit depth is read from the library. Note that there + * are interactions with sBIT but, internally, libpng makes sbit at most + * PNG_MAX_GAMMA_8 when doing the following. + */ + if (dp->scale16) +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(pp); +# else + /* The following works both in 1.5.4 and earlier versions: */ +# ifdef PNG_READ_16_TO_8_SUPPORTED + png_set_strip_16(pp); +# else + png_error(pp, "scale16 (16 to 8 bit conversion) not supported"); +# endif +# endif + + if (dp->expand16) +# ifdef PNG_READ_EXPAND_16_SUPPORTED + png_set_expand_16(pp); +# else + png_error(pp, "expand16 (8 to 16 bit conversion) not supported"); +# endif + + if (dp->do_background >= ALPHA_MODE_OFFSET) + { +# ifdef PNG_READ_ALPHA_MODE_SUPPORTED + { + /* This tests the alpha mode handling, if supported. */ + int mode = dp->do_background - ALPHA_MODE_OFFSET; + + /* The gamma value is the output gamma, and is in the standard, + * non-inverted, represenation. It provides a default for the PNG file + * gamma, but since the file has a gAMA chunk this does not matter. + */ + PNG_CONST double sg = dp->screen_gamma; +# ifndef PNG_FLOATING_POINT_SUPPORTED + PNG_CONST png_fixed_point g = fix(sg); +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_alpha_mode(pp, mode, sg); +# else + png_set_alpha_mode_fixed(pp, mode, g); +# endif + + /* However, for the standard Porter-Duff algorithm the output defaults + * to be linear, so if the test requires non-linear output it must be + * corrected here. + */ + if (mode == PNG_ALPHA_STANDARD && sg != 1) + { +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_gamma(pp, sg, dp->file_gamma); +# else + png_fixed_point f = fix(dp->file_gamma); + png_set_gamma_fixed(pp, g, f); +# endif + } + } +# else + png_error(pp, "alpha mode handling not supported"); +# endif + } + + else + { + /* Set up gamma processing. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_gamma(pp, dp->screen_gamma, dp->file_gamma); +# else + { + png_fixed_point s = fix(dp->screen_gamma); + png_fixed_point f = fix(dp->file_gamma); + png_set_gamma_fixed(pp, s, f); + } +# endif + + if (dp->do_background) + { +# ifdef PNG_READ_BACKGROUND_SUPPORTED + /* NOTE: this assumes the caller provided the correct background gamma! + */ + PNG_CONST double bg = dp->background_gamma; +# ifndef PNG_FLOATING_POINT_SUPPORTED + PNG_CONST png_fixed_point g = fix(bg); +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_background(pp, &dp->background_color, dp->do_background, + 0/*need_expand*/, bg); +# else + png_set_background_fixed(pp, &dp->background_color, + dp->do_background, 0/*need_expand*/, g); +# endif +# else + png_error(pp, "png_set_background not supported"); +# endif + } + } + + { + int i = dp->this.use_update_info; + /* Always do one call, even if use_update_info is 0. */ + do + png_read_update_info(pp, pi); + while (--i > 0); + } + + /* Now we may get a different cbRow: */ + standard_info_part2(&dp->this, pp, pi, 1 /*images*/); +} + +static void +gamma_info(png_structp pp, png_infop pi) +{ + gamma_info_imp(voidcast(gamma_display*, png_get_progressive_ptr(pp)), pp, + pi); +} + +/* Validate a single component value - the routine gets the input and output + * sample values as unscaled PNG component values along with a cache of all the + * information required to validate the values. + */ +typedef struct validate_info +{ + png_const_structp pp; + gamma_display *dp; + png_byte sbit; + int use_input_precision; + int do_background; + int scale16; + unsigned int sbit_max; + unsigned int isbit_shift; + unsigned int outmax; + + double gamma_correction; /* Overall correction required. */ + double file_inverse; /* Inverse of file gamma. */ + double screen_gamma; + double screen_inverse; /* Inverse of screen gamma. */ + + double background_red; /* Linear background value, red or gray. */ + double background_green; + double background_blue; + + double maxabs; + double maxpc; + double maxcalc; + double maxout; + double maxout_total; /* Total including quantization error */ + double outlog; + int outquant; +} +validate_info; + +static void +init_validate_info(validate_info *vi, gamma_display *dp, png_const_structp pp, + int in_depth, int out_depth) +{ + PNG_CONST unsigned int outmax = (1U<pp = pp; + vi->dp = dp; + + if (dp->sbit > 0 && dp->sbit < in_depth) + { + vi->sbit = dp->sbit; + vi->isbit_shift = in_depth - dp->sbit; + } + + else + { + vi->sbit = (png_byte)in_depth; + vi->isbit_shift = 0; + } + + vi->sbit_max = (1U << vi->sbit)-1; + + /* This mimics the libpng threshold test, '0' is used to prevent gamma + * correction in the validation test. + */ + vi->screen_gamma = dp->screen_gamma; + if (fabs(vi->screen_gamma-1) < PNG_GAMMA_THRESHOLD) + vi->screen_gamma = vi->screen_inverse = 0; + else + vi->screen_inverse = 1/vi->screen_gamma; + + vi->use_input_precision = dp->use_input_precision; + vi->outmax = outmax; + vi->maxabs = abserr(dp->pm, in_depth, out_depth); + vi->maxpc = pcerr(dp->pm, in_depth, out_depth); + vi->maxcalc = calcerr(dp->pm, in_depth, out_depth); + vi->maxout = outerr(dp->pm, in_depth, out_depth); + vi->outquant = output_quantization_factor(dp->pm, in_depth, out_depth); + vi->maxout_total = vi->maxout + vi->outquant * .5; + vi->outlog = outlog(dp->pm, in_depth, out_depth); + + if ((dp->this.colour_type & PNG_COLOR_MASK_ALPHA) != 0 || + (dp->this.colour_type == 3 && dp->this.is_transparent)) + { + vi->do_background = dp->do_background; + + if (vi->do_background != 0) + { + PNG_CONST double bg_inverse = 1/dp->background_gamma; + double r, g, b; + + /* Caller must at least put the gray value into the red channel */ + r = dp->background_color.red; r /= outmax; + g = dp->background_color.green; g /= outmax; + b = dp->background_color.blue; b /= outmax; + +# if 0 + /* libpng doesn't do this optimization, if we do pngvalid will fail. + */ + if (fabs(bg_inverse-1) >= PNG_GAMMA_THRESHOLD) +# endif + { + r = pow(r, bg_inverse); + g = pow(g, bg_inverse); + b = pow(b, bg_inverse); + } + + vi->background_red = r; + vi->background_green = g; + vi->background_blue = b; + } + } + else + vi->do_background = 0; + + if (vi->do_background == 0) + vi->background_red = vi->background_green = vi->background_blue = 0; + + vi->gamma_correction = 1/(dp->file_gamma*dp->screen_gamma); + if (fabs(vi->gamma_correction-1) < PNG_GAMMA_THRESHOLD) + vi->gamma_correction = 0; + + vi->file_inverse = 1/dp->file_gamma; + if (fabs(vi->file_inverse-1) < PNG_GAMMA_THRESHOLD) + vi->file_inverse = 0; + + vi->scale16 = dp->scale16; +} + +/* This function handles composition of a single non-alpha component. The + * argument is the input sample value, in the range 0..1, and the alpha value. + * The result is the composed, linear, input sample. If alpha is less than zero + * this is the alpha component and the function should not be called! + */ +static double +gamma_component_compose(int do_background, double input_sample, double alpha, + double background, int *compose) +{ + switch (do_background) + { +#ifdef PNG_READ_BACKGROUND_SUPPORTED + case PNG_BACKGROUND_GAMMA_SCREEN: + case PNG_BACKGROUND_GAMMA_FILE: + case PNG_BACKGROUND_GAMMA_UNIQUE: + /* Standard PNG background processing. */ + if (alpha < 1) + { + if (alpha > 0) + { + input_sample = input_sample * alpha + background * (1-alpha); + if (compose != NULL) + *compose = 1; + } + + else + input_sample = background; + } + break; +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: + case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: + /* The components are premultiplied in either case and the output is + * gamma encoded (to get standard Porter-Duff we expect the output + * gamma to be set to 1.0!) + */ + case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: + /* The optimization is that the partial-alpha entries are linear + * while the opaque pixels are gamma encoded, but this only affects the + * output encoding. + */ + if (alpha < 1) + { + if (alpha > 0) + { + input_sample *= alpha; + if (compose != NULL) + *compose = 1; + } + + else + input_sample = 0; + } + break; +#endif + + default: + /* Standard cases where no compositing is done (so the component + * value is already correct.) + */ + UNUSED(alpha) + UNUSED(background) + UNUSED(compose) + break; + } + + return input_sample; +} + +/* This API returns the encoded *input* component, in the range 0..1 */ +static double +gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi, + PNG_CONST unsigned int id, PNG_CONST unsigned int od, + PNG_CONST double alpha /* <0 for the alpha channel itself */, + PNG_CONST double background /* component background value */) +{ + PNG_CONST unsigned int isbit = id >> vi->isbit_shift; + PNG_CONST unsigned int sbit_max = vi->sbit_max; + PNG_CONST unsigned int outmax = vi->outmax; + PNG_CONST int do_background = vi->do_background; + + double i; + + /* First check on the 'perfect' result obtained from the digitized input + * value, id, and compare this against the actual digitized result, 'od'. + * 'i' is the input result in the range 0..1: + */ + i = isbit; i /= sbit_max; + + /* Check for the fast route: if we don't do any background composition or if + * this is the alpha channel ('alpha' < 0) or if the pixel is opaque then + * just use the gamma_correction field to correct to the final output gamma. + */ + if (alpha == 1 /* opaque pixel component */ || !do_background +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + || do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_PNG +#endif + || (alpha < 0 /* alpha channel */ +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + && do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN +#endif + )) + { + /* Then get the gamma corrected version of 'i' and compare to 'od', any + * error less than .5 is insignificant - just quantization of the output + * value to the nearest digital value (nevertheless the error is still + * recorded - it's interesting ;-) + */ + double encoded_sample = i; + double encoded_error; + + /* alpha less than 0 indicates the alpha channel, which is always linear + */ + if (alpha >= 0 && vi->gamma_correction > 0) + encoded_sample = pow(encoded_sample, vi->gamma_correction); + encoded_sample *= outmax; + + encoded_error = fabs(od-encoded_sample); + + if (encoded_error > vi->dp->maxerrout) + vi->dp->maxerrout = encoded_error; + + if (encoded_error < vi->maxout_total && encoded_error < vi->outlog) + return i; + } + + /* The slow route - attempt to do linear calculations. */ + /* There may be an error, or background processing is required, so calculate + * the actual sample values - unencoded light intensity values. Note that in + * practice these are not completely unencoded because they include a + * 'viewing correction' to decrease or (normally) increase the perceptual + * contrast of the image. There's nothing we can do about this - we don't + * know what it is - so assume the unencoded value is perceptually linear. + */ + { + double input_sample = i; /* In range 0..1 */ + double output, error, encoded_sample, encoded_error; + double es_lo, es_hi; + int compose = 0; /* Set to one if composition done */ + int output_is_encoded; /* Set if encoded to screen gamma */ + int log_max_error = 1; /* Check maximum error values */ + png_const_charp pass = 0; /* Reason test passes (or 0 for fail) */ + + /* Convert to linear light (with the above caveat.) The alpha channel is + * already linear. + */ + if (alpha >= 0) + { + int tcompose; + + if (vi->file_inverse > 0) + input_sample = pow(input_sample, vi->file_inverse); + + /* Handle the compose processing: */ + tcompose = 0; + input_sample = gamma_component_compose(do_background, input_sample, + alpha, background, &tcompose); + + if (tcompose) + compose = 1; + } + + /* And similarly for the output value, but we need to check the background + * handling to linearize it correctly. + */ + output = od; + output /= outmax; + + output_is_encoded = vi->screen_gamma > 0; + + if (alpha < 0) /* The alpha channel */ + { +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if (do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN) +#endif + { + /* In all other cases the output alpha channel is linear already, + * don't log errors here, they are much larger in linear data. + */ + output_is_encoded = 0; + log_max_error = 0; + } + } + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + else /* A component */ + { + if (do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED && + alpha < 1) /* the optimized case - linear output */ + { + if (alpha > 0) log_max_error = 0; + output_is_encoded = 0; + } + } +#endif + + if (output_is_encoded) + output = pow(output, vi->screen_gamma); + + /* Calculate (or recalculate) the encoded_sample value and repeat the + * check above (unnecessary if we took the fast route, but harmless.) + */ + encoded_sample = input_sample; + if (output_is_encoded) + encoded_sample = pow(encoded_sample, vi->screen_inverse); + encoded_sample *= outmax; + + encoded_error = fabs(od-encoded_sample); + + /* Don't log errors in the alpha channel, or the 'optimized' case, + * neither are significant to the overall perception. + */ + if (log_max_error && encoded_error > vi->dp->maxerrout) + vi->dp->maxerrout = encoded_error; + + if (encoded_error < vi->maxout_total) + { + if (encoded_error < vi->outlog) + return i; + + /* Test passed but error is bigger than the log limit, record why the + * test passed: + */ + pass = "less than maxout:\n"; + } + + /* i: the original input value in the range 0..1 + * + * pngvalid calculations: + * input_sample: linear result; i linearized and composed, range 0..1 + * encoded_sample: encoded result; input_sample scaled to ouput bit depth + * + * libpng calculations: + * output: linear result; od scaled to 0..1 and linearized + * od: encoded result from libpng + */ + + /* Now we have the numbers for real errors, both absolute values as as a + * percentage of the correct value (output): + */ + error = fabs(input_sample-output); + + if (log_max_error && error > vi->dp->maxerrabs) + vi->dp->maxerrabs = error; + + /* The following is an attempt to ignore the tendency of quantization to + * dominate the percentage errors for lower result values: + */ + if (log_max_error && input_sample > .5) + { + double percentage_error = error/input_sample; + if (percentage_error > vi->dp->maxerrpc) + vi->dp->maxerrpc = percentage_error; + } + + /* Now calculate the digitization limits for 'encoded_sample' using the + * 'max' values. Note that maxout is in the encoded space but maxpc and + * maxabs are in linear light space. + * + * First find the maximum error in linear light space, range 0..1: + */ + { + double tmp = input_sample * vi->maxpc; + if (tmp < vi->maxabs) tmp = vi->maxabs; + /* If 'compose' is true the composition was done in linear space using + * integer arithmetic. This introduces an extra error of +/- 0.5 (at + * least) in the integer space used. 'maxcalc' records this, taking + * into account the possibility that even for 16 bit output 8 bit space + * may have been used. + */ + if (compose && tmp < vi->maxcalc) tmp = vi->maxcalc; + + /* The 'maxout' value refers to the encoded result, to compare with + * this encode input_sample adjusted by the maximum error (tmp) above. + */ + es_lo = encoded_sample - vi->maxout; + + if (es_lo > 0 && input_sample-tmp > 0) + { + double low_value = input_sample-tmp; + if (output_is_encoded) + low_value = pow(low_value, vi->screen_inverse); + low_value *= outmax; + if (low_value < es_lo) es_lo = low_value; + + /* Quantize this appropriately: */ + es_lo = ceil(es_lo / vi->outquant - .5) * vi->outquant; + } + + else + es_lo = 0; + + es_hi = encoded_sample + vi->maxout; + + if (es_hi < outmax && input_sample+tmp < 1) + { + double high_value = input_sample+tmp; + if (output_is_encoded) + high_value = pow(high_value, vi->screen_inverse); + high_value *= outmax; + if (high_value > es_hi) es_hi = high_value; + + es_hi = floor(es_hi / vi->outquant + .5) * vi->outquant; + } + + else + es_hi = outmax; + } + + /* The primary test is that the final encoded value returned by the + * library should be between the two limits (inclusive) that were + * calculated above. + */ + if (od >= es_lo && od <= es_hi) + { + /* The value passes, but we may need to log the information anyway. */ + if (encoded_error < vi->outlog) + return i; + + if (pass == 0) + pass = "within digitization limits:\n"; + } + + { + /* There has been an error in processing, or we need to log this + * value. + */ + double is_lo, is_hi; + + /* pass is set at this point if either of the tests above would have + * passed. Don't do these additional tests here - just log the + * original [es_lo..es_hi] values. + */ + if (pass == 0 && vi->use_input_precision) + { + /* Ok, something is wrong - this actually happens in current libpng + * 16-to-8 processing. Assume that the input value (id, adjusted + * for sbit) can be anywhere between value-.5 and value+.5 - quite a + * large range if sbit is low. + */ + double tmp = (isbit - .5)/sbit_max; + + if (tmp <= 0) + tmp = 0; + + else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1) + tmp = pow(tmp, vi->file_inverse); + + tmp = gamma_component_compose(do_background, tmp, alpha, background, + NULL); + + if (output_is_encoded && tmp > 0 && tmp < 1) + tmp = pow(tmp, vi->screen_inverse); + + is_lo = ceil(outmax * tmp - vi->maxout_total); + + if (is_lo < 0) + is_lo = 0; + + tmp = (isbit + .5)/sbit_max; + + if (tmp <= 0) + tmp = 0; + + else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1) + tmp = pow(tmp, vi->file_inverse); + + tmp = gamma_component_compose(do_background, tmp, alpha, background, + NULL); + + if (output_is_encoded && tmp > 0 && tmp < 1) + tmp = pow(tmp, vi->screen_inverse); + + is_hi = floor(outmax * tmp + vi->maxout_total); + + if (is_hi > outmax) + is_hi = outmax; + + if (!(od < is_lo || od > is_hi)) + { + if (encoded_error < vi->outlog) + return i; + + pass = "within input precision limits:\n"; + } + + /* One last chance. If this is an alpha channel and the 16to8 + * option has been used and 'inaccurate' scaling is used then the + * bit reduction is obtained by simply using the top 8 bits of the + * value. + * + * This is only done for older libpng versions when the 'inaccurate' + * (chop) method of scaling was used. + */ +# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# if PNG_LIBPNG_VER < 10504 + /* This may be required for other components in the future, + * but at present the presence of gamma correction effectively + * prevents the errors in the component scaling (I don't quite + * understand why, but since it's better this way I care not + * to ask, JB 20110419.) + */ + if (pass == 0 && alpha < 0 && vi->scale16 && vi->sbit > 8 && + vi->sbit + vi->isbit_shift == 16) + { + tmp = ((id >> 8) - .5)/255; + + if (tmp > 0) + { + is_lo = ceil(outmax * tmp - vi->maxout_total); + if (is_lo < 0) is_lo = 0; + } + + else + is_lo = 0; + + tmp = ((id >> 8) + .5)/255; + + if (tmp < 1) + { + is_hi = floor(outmax * tmp + vi->maxout_total); + if (is_hi > outmax) is_hi = outmax; + } + + else + is_hi = outmax; + + if (!(od < is_lo || od > is_hi)) + { + if (encoded_error < vi->outlog) + return i; + + pass = "within 8 bit limits:\n"; + } + } +# endif +# endif + } + else /* !use_input_precision */ + is_lo = es_lo, is_hi = es_hi; + + /* Attempt to output a meaningful error/warning message: the message + * output depends on the background/composite operation being performed + * because this changes what parameters were actually used above. + */ + { + size_t pos = 0; + /* Need either 1/255 or 1/65535 precision here; 3 or 6 decimal + * places. Just use outmax to work out which. + */ + int precision = (outmax >= 1000 ? 6 : 3); + int use_input=1, use_background=0, do_compose=0; + char msg[256]; + + if (pass != 0) + pos = safecat(msg, sizeof msg, pos, "\n\t"); + + /* Set up the various flags, the output_is_encoded flag above + * is also used below. do_compose is just a double check. + */ + switch (do_background) + { +# ifdef PNG_READ_BACKGROUND_SUPPORTED + case PNG_BACKGROUND_GAMMA_SCREEN: + case PNG_BACKGROUND_GAMMA_FILE: + case PNG_BACKGROUND_GAMMA_UNIQUE: + use_background = (alpha >= 0 && alpha < 1); + /*FALL THROUGH*/ +# endif +# ifdef PNG_READ_ALPHA_MODE_SUPPORTED + case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: + case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: + case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: +# endif /* ALPHA_MODE_SUPPORTED */ + do_compose = (alpha > 0 && alpha < 1); + use_input = (alpha != 0); + break; + + default: + break; + } + + /* Check the 'compose' flag */ + if (compose != do_compose) + png_error(vi->pp, "internal error (compose)"); + + /* 'name' is the component name */ + pos = safecat(msg, sizeof msg, pos, name); + pos = safecat(msg, sizeof msg, pos, "("); + pos = safecatn(msg, sizeof msg, pos, id); + if (use_input || pass != 0/*logging*/) + { + if (isbit != id) + { + /* sBIT has reduced the precision of the input: */ + pos = safecat(msg, sizeof msg, pos, ", sbit("); + pos = safecatn(msg, sizeof msg, pos, vi->sbit); + pos = safecat(msg, sizeof msg, pos, "): "); + pos = safecatn(msg, sizeof msg, pos, isbit); + } + pos = safecat(msg, sizeof msg, pos, "/"); + /* The output is either "id/max" or "id sbit(sbit): isbit/max" */ + pos = safecatn(msg, sizeof msg, pos, vi->sbit_max); + } + pos = safecat(msg, sizeof msg, pos, ")"); + + /* A component may have been multiplied (in linear space) by the + * alpha value, 'compose' says whether this is relevant. + */ + if (compose || pass != 0) + { + /* If any form of composition is being done report our + * calculated linear value here (the code above doesn't record + * the input value before composition is performed, so what + * gets reported is the value after composition.) + */ + if (use_input || pass != 0) + { + if (vi->file_inverse > 0) + { + pos = safecat(msg, sizeof msg, pos, "^"); + pos = safecatd(msg, sizeof msg, pos, vi->file_inverse, 2); + } + + else + pos = safecat(msg, sizeof msg, pos, "[linear]"); + + pos = safecat(msg, sizeof msg, pos, "*(alpha)"); + pos = safecatd(msg, sizeof msg, pos, alpha, precision); + } + + /* Now record the *linear* background value if it was used + * (this function is not passed the original, non-linear, + * value but it is contained in the test name.) + */ + if (use_background) + { + pos = safecat(msg, sizeof msg, pos, use_input ? "+" : " "); + pos = safecat(msg, sizeof msg, pos, "(background)"); + pos = safecatd(msg, sizeof msg, pos, background, precision); + pos = safecat(msg, sizeof msg, pos, "*"); + pos = safecatd(msg, sizeof msg, pos, 1-alpha, precision); + } + } + + /* Report the calculated value (input_sample) and the linearized + * libpng value (output) unless this is just a component gamma + * correction. + */ + if (compose || alpha < 0 || pass != 0) + { + pos = safecat(msg, sizeof msg, pos, + pass != 0 ? " =\n\t" : " = "); + pos = safecatd(msg, sizeof msg, pos, input_sample, precision); + pos = safecat(msg, sizeof msg, pos, " (libpng: "); + pos = safecatd(msg, sizeof msg, pos, output, precision); + pos = safecat(msg, sizeof msg, pos, ")"); + + /* Finally report the output gamma encoding, if any. */ + if (output_is_encoded) + { + pos = safecat(msg, sizeof msg, pos, " ^"); + pos = safecatd(msg, sizeof msg, pos, vi->screen_inverse, 2); + pos = safecat(msg, sizeof msg, pos, "(to screen) ="); + } + + else + pos = safecat(msg, sizeof msg, pos, " [screen is linear] ="); + } + + if ((!compose && alpha >= 0) || pass != 0) + { + if (pass != 0) /* logging */ + pos = safecat(msg, sizeof msg, pos, "\n\t[overall:"); + + /* This is the non-composition case, the internal linear + * values are irrelevant (though the log below will reveal + * them.) Output a much shorter warning/error message and report + * the overall gamma correction. + */ + if (vi->gamma_correction > 0) + { + pos = safecat(msg, sizeof msg, pos, " ^"); + pos = safecatd(msg, sizeof msg, pos, vi->gamma_correction, 2); + pos = safecat(msg, sizeof msg, pos, "(gamma correction) ="); + } + + else + pos = safecat(msg, sizeof msg, pos, + " [no gamma correction] ="); + + if (pass != 0) + pos = safecat(msg, sizeof msg, pos, "]"); + } + + /* This is our calculated encoded_sample which should (but does + * not) match od: + */ + pos = safecat(msg, sizeof msg, pos, pass != 0 ? "\n\t" : " "); + pos = safecatd(msg, sizeof msg, pos, is_lo, 1); + pos = safecat(msg, sizeof msg, pos, " < "); + pos = safecatd(msg, sizeof msg, pos, encoded_sample, 1); + pos = safecat(msg, sizeof msg, pos, " (libpng: "); + pos = safecatn(msg, sizeof msg, pos, od); + pos = safecat(msg, sizeof msg, pos, ")"); + pos = safecat(msg, sizeof msg, pos, "/"); + pos = safecatn(msg, sizeof msg, pos, outmax); + pos = safecat(msg, sizeof msg, pos, " < "); + pos = safecatd(msg, sizeof msg, pos, is_hi, 1); + + if (pass == 0) /* The error condition */ + { +# ifdef PNG_WARNINGS_SUPPORTED + png_warning(vi->pp, msg); +# else + store_warning(vi->pp, msg); +# endif + } + + else /* logging this value */ + store_verbose(&vi->dp->pm->this, vi->pp, pass, msg); + } + } + } + + return i; +} + +static void +gamma_image_validate(gamma_display *dp, png_const_structp pp, + png_infop pi) +{ + /* Get some constants derived from the input and output file formats: */ + PNG_CONST png_store* PNG_CONST ps = dp->this.ps; + PNG_CONST png_byte in_ct = dp->this.colour_type; + PNG_CONST png_byte in_bd = dp->this.bit_depth; + PNG_CONST png_uint_32 w = dp->this.w; + PNG_CONST png_uint_32 h = dp->this.h; + PNG_CONST size_t cbRow = dp->this.cbRow; + PNG_CONST png_byte out_ct = png_get_color_type(pp, pi); + PNG_CONST png_byte out_bd = png_get_bit_depth(pp, pi); + + /* There are three sources of error, firstly the quantization in the + * file encoding, determined by sbit and/or the file depth, secondly + * the output (screen) gamma and thirdly the output file encoding. + * + * Since this API receives the screen and file gamma in double + * precision it is possible to calculate an exact answer given an input + * pixel value. Therefore we assume that the *input* value is exact - + * sample/maxsample - calculate the corresponding gamma corrected + * output to the limits of double precision arithmetic and compare with + * what libpng returns. + * + * Since the library must quantize the output to 8 or 16 bits there is + * a fundamental limit on the accuracy of the output of +/-.5 - this + * quantization limit is included in addition to the other limits + * specified by the paramaters to the API. (Effectively, add .5 + * everywhere.) + * + * The behavior of the 'sbit' paramter is defined by section 12.5 + * (sample depth scaling) of the PNG spec. That section forces the + * decoder to assume that the PNG values have been scaled if sBIT is + * present: + * + * png-sample = floor( input-sample * (max-out/max-in) + .5); + * + * This means that only a subset of the possible PNG values should + * appear in the input. However, the spec allows the encoder to use a + * variety of approximations to the above and doesn't require any + * restriction of the values produced. + * + * Nevertheless the spec requires that the upper 'sBIT' bits of the + * value stored in a PNG file be the original sample bits. + * Consequently the code below simply scales the top sbit bits by + * (1<this.palette; + PNG_CONST int in_is_transparent = dp->this.is_transparent; + int out_npalette = -1; + int out_is_transparent = 0; /* Just refers to the palette case */ + store_palette out_palette; + validate_info vi; + + /* Check for row overwrite errors */ + store_image_check(dp->this.ps, pp, 0); + + /* Supply the input and output sample depths here - 8 for an indexed image, + * otherwise the bit depth. + */ + init_validate_info(&vi, dp, pp, in_ct==3?8:in_bd, out_ct==3?8:out_bd); + + processing = (vi.gamma_correction > 0 && !dp->threshold_test) + || in_bd != out_bd || in_ct != out_ct || vi.do_background; + + /* TODO: FIX THIS: MAJOR BUG! If the transformations all happen inside + * the palette there is no way of finding out, because libpng fails to + * update the palette on png_read_update_info. Indeed, libpng doesn't + * even do the required work until much later, when it doesn't have any + * info pointer. Oops. For the moment 'processing' is turned off if + * out_ct is palette. + */ + if (in_ct == 3 && out_ct == 3) + processing = 0; + + if (processing && out_ct == 3) + out_is_transparent = read_palette(out_palette, &out_npalette, pp, pi); + + for (y=0; ythis.palette[in_index].alpha : + sample(std, in_ct, in_bd, x, samples_per_pixel); + + unsigned int output_alpha = 65536 /* as a flag value */; + + if (out_ct == 3) + { + if (out_is_transparent) + output_alpha = out_palette[out_index].alpha; + } + + else if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0) + output_alpha = sample(pRow, out_ct, out_bd, x, + samples_per_pixel); + + if (output_alpha != 65536) + alpha = gamma_component_validate("alpha", &vi, input_alpha, + output_alpha, -1/*alpha*/, 0/*background*/); + + else /* no alpha in output */ + { + /* This is a copy of the calculation of 'i' above in order to + * have the alpha value to use in the background calculation. + */ + alpha = input_alpha >> vi.isbit_shift; + alpha /= vi.sbit_max; + } + } + + /* Handle grayscale or RGB components. */ + if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* grayscale */ + (void)gamma_component_validate("gray", &vi, + sample(std, in_ct, in_bd, x, 0), + sample(pRow, out_ct, out_bd, x, 0), alpha/*component*/, + vi.background_red); + else /* RGB or palette */ + { + (void)gamma_component_validate("red", &vi, + in_ct == 3 ? in_palette[in_index].red : + sample(std, in_ct, in_bd, x, 0), + out_ct == 3 ? out_palette[out_index].red : + sample(pRow, out_ct, out_bd, x, 0), + alpha/*component*/, vi.background_red); + + (void)gamma_component_validate("green", &vi, + in_ct == 3 ? in_palette[in_index].green : + sample(std, in_ct, in_bd, x, 1), + out_ct == 3 ? out_palette[out_index].green : + sample(pRow, out_ct, out_bd, x, 1), + alpha/*component*/, vi.background_green); + + (void)gamma_component_validate("blue", &vi, + in_ct == 3 ? in_palette[in_index].blue : + sample(std, in_ct, in_bd, x, 2), + out_ct == 3 ? out_palette[out_index].blue : + sample(pRow, out_ct, out_bd, x, 2), + alpha/*component*/, vi.background_blue); + } + } + } + + else if (memcmp(std, pRow, cbRow) != 0) + { + char msg[64]; + + /* No transform is expected on the threshold tests. */ + sprintf(msg, "gamma: below threshold row %lu changed", + (unsigned long)y); + + png_error(pp, msg); + } + } /* row (y) loop */ + + dp->this.ps->validated = 1; +} + +static void +gamma_end(png_structp ppIn, png_infop pi) +{ + png_const_structp pp = ppIn; + gamma_display *dp = voidcast(gamma_display*, png_get_progressive_ptr(pp)); + + if (!dp->this.speed) + gamma_image_validate(dp, pp, pi); + else + dp->this.ps->validated = 1; +} + +/* A single test run checking a gamma transformation. + * + * maxabs: maximum absolute error as a fraction + * maxout: maximum output error in the output units + * maxpc: maximum percentage error (as a percentage) + */ +static void +gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn, + PNG_CONST png_byte bit_depthIn, PNG_CONST int palette_numberIn, + PNG_CONST int interlace_typeIn, + PNG_CONST double file_gammaIn, PNG_CONST double screen_gammaIn, + PNG_CONST png_byte sbitIn, PNG_CONST int threshold_testIn, + PNG_CONST char *name, + PNG_CONST int use_input_precisionIn, PNG_CONST int scale16In, + PNG_CONST int expand16In, PNG_CONST int do_backgroundIn, + PNG_CONST png_color_16 *bkgd_colorIn, double bkgd_gammaIn) +{ + gamma_display d; + context(&pmIn->this, fault); + + gamma_display_init(&d, pmIn, FILEID(colour_typeIn, bit_depthIn, + palette_numberIn, interlace_typeIn, 0, 0, 0), + file_gammaIn, screen_gammaIn, sbitIn, + threshold_testIn, use_input_precisionIn, scale16In, + expand16In, do_backgroundIn, bkgd_colorIn, bkgd_gammaIn); + + Try + { + png_structp pp; + png_infop pi; + gama_modification gama_mod; + srgb_modification srgb_mod; + sbit_modification sbit_mod; + + /* For the moment don't use the png_modifier support here. */ + d.pm->encoding_counter = 0; + modifier_set_encoding(d.pm); /* Just resets everything */ + d.pm->current_gamma = d.file_gamma; + + /* Make an appropriate modifier to set the PNG file gamma to the + * given gamma value and the sBIT chunk to the given precision. + */ + d.pm->modifications = NULL; + gama_modification_init(&gama_mod, d.pm, d.file_gamma); + srgb_modification_init(&srgb_mod, d.pm, 127 /*delete*/); + if (d.sbit > 0) + sbit_modification_init(&sbit_mod, d.pm, d.sbit); + + modification_reset(d.pm->modifications); + + /* Get a png_struct for writing the image. */ + pp = set_modifier_for_read(d.pm, &pi, d.this.id, name); + standard_palette_init(&d.this); + + /* Introduce the correct read function. */ + if (d.pm->this.progressive) + { + /* Share the row function with the standard implementation. */ + png_set_progressive_read_fn(pp, &d, gamma_info, progressive_row, + gamma_end); + + /* Now feed data into the reader until we reach the end: */ + modifier_progressive_read(d.pm, pp, pi); + } + else + { + /* modifier_read expects a png_modifier* */ + png_set_read_fn(pp, d.pm, modifier_read); + + /* Check the header values: */ + png_read_info(pp, pi); + + /* Process the 'info' requirements. Only one image is generated */ + gamma_info_imp(&d, pp, pi); + + sequential_row(&d.this, pp, pi, -1, 0); + + if (!d.this.speed) + gamma_image_validate(&d, pp, pi); + else + d.this.ps->validated = 1; + } + + modifier_reset(d.pm); + + if (d.pm->log && !d.threshold_test && !d.this.speed) + fprintf(stderr, "%d bit %s %s: max error %f (%.2g, %2g%%)\n", + d.this.bit_depth, colour_types[d.this.colour_type], name, + d.maxerrout, d.maxerrabs, 100*d.maxerrpc); + + /* Log the summary values too. */ + if (d.this.colour_type == 0 || d.this.colour_type == 4) + { + switch (d.this.bit_depth) + { + case 1: + break; + + case 2: + if (d.maxerrout > d.pm->error_gray_2) + d.pm->error_gray_2 = d.maxerrout; + + break; + + case 4: + if (d.maxerrout > d.pm->error_gray_4) + d.pm->error_gray_4 = d.maxerrout; + + break; + + case 8: + if (d.maxerrout > d.pm->error_gray_8) + d.pm->error_gray_8 = d.maxerrout; + + break; + + case 16: + if (d.maxerrout > d.pm->error_gray_16) + d.pm->error_gray_16 = d.maxerrout; + + break; + + default: + png_error(pp, "bad bit depth (internal: 1)"); + } + } + + else if (d.this.colour_type == 2 || d.this.colour_type == 6) + { + switch (d.this.bit_depth) + { + case 8: + + if (d.maxerrout > d.pm->error_color_8) + d.pm->error_color_8 = d.maxerrout; + + break; + + case 16: + + if (d.maxerrout > d.pm->error_color_16) + d.pm->error_color_16 = d.maxerrout; + + break; + + default: + png_error(pp, "bad bit depth (internal: 2)"); + } + } + + else if (d.this.colour_type == 3) + { + if (d.maxerrout > d.pm->error_indexed) + d.pm->error_indexed = d.maxerrout; + } + } + + Catch(fault) + modifier_reset((png_modifier*)fault); +} + +static void gamma_threshold_test(png_modifier *pm, png_byte colour_type, + png_byte bit_depth, int interlace_type, double file_gamma, + double screen_gamma) +{ + size_t pos = 0; + char name[64]; + pos = safecat(name, sizeof name, pos, "threshold "); + pos = safecatd(name, sizeof name, pos, file_gamma, 3); + pos = safecat(name, sizeof name, pos, "/"); + pos = safecatd(name, sizeof name, pos, screen_gamma, 3); + + (void)gamma_test(pm, colour_type, bit_depth, 0/*palette*/, interlace_type, + file_gamma, screen_gamma, 0/*sBIT*/, 1/*threshold test*/, name, + 0 /*no input precision*/, + 0 /*no scale16*/, 0 /*no expand16*/, 0 /*no background*/, 0 /*hence*/, + 0 /*no background gamma*/); +} + +static void +perform_gamma_threshold_tests(png_modifier *pm) +{ + png_byte colour_type = 0; + png_byte bit_depth = 0; + unsigned int palette_number = 0; + + /* Don't test more than one instance of each palette - it's pointless, in + * fact this test is somewhat excessive since libpng doesn't make this + * decision based on colour type or bit depth! + */ + while (next_format(&colour_type, &bit_depth, &palette_number)) + if (palette_number == 0) + { + double test_gamma = 1.0; + while (test_gamma >= .4) + { + /* There's little point testing the interlacing vs non-interlacing, + * but this can be set from the command line. + */ + gamma_threshold_test(pm, colour_type, bit_depth, pm->interlace_type, + test_gamma, 1/test_gamma); + test_gamma *= .95; + } + + /* And a special test for sRGB */ + gamma_threshold_test(pm, colour_type, bit_depth, pm->interlace_type, + .45455, 2.2); + + if (fail(pm)) + return; + } +} + +static void gamma_transform_test(png_modifier *pm, + PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth, + PNG_CONST int palette_number, + PNG_CONST int interlace_type, PNG_CONST double file_gamma, + PNG_CONST double screen_gamma, PNG_CONST png_byte sbit, + PNG_CONST int use_input_precision, PNG_CONST int scale16) +{ + size_t pos = 0; + char name[64]; + + if (sbit != bit_depth && sbit != 0) + { + pos = safecat(name, sizeof name, pos, "sbit("); + pos = safecatn(name, sizeof name, pos, sbit); + pos = safecat(name, sizeof name, pos, ") "); + } + + else + pos = safecat(name, sizeof name, pos, "gamma "); + + if (scale16) + pos = safecat(name, sizeof name, pos, "16to8 "); + + pos = safecatd(name, sizeof name, pos, file_gamma, 3); + pos = safecat(name, sizeof name, pos, "->"); + pos = safecatd(name, sizeof name, pos, screen_gamma, 3); + + gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type, + file_gamma, screen_gamma, sbit, 0, name, use_input_precision, + scale16, pm->test_gamma_expand16, 0 , 0, 0); +} + +static void perform_gamma_transform_tests(png_modifier *pm) +{ + png_byte colour_type = 0; + png_byte bit_depth = 0; + unsigned int palette_number = 0; + + while (next_format(&colour_type, &bit_depth, &palette_number)) + { + unsigned int i, j; + + for (i=0; ingamma_tests; ++i) for (j=0; jngamma_tests; ++j) + if (i != j) + { + gamma_transform_test(pm, colour_type, bit_depth, palette_number, + pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 0/*sBIT*/, + pm->use_input_precision, 0 /*do not scale16*/); + + if (fail(pm)) + return; + } + } +} + +static void perform_gamma_sbit_tests(png_modifier *pm) +{ + png_byte sbit; + + /* The only interesting cases are colour and grayscale, alpha is ignored here + * for overall speed. Only bit depths where sbit is less than the bit depth + * are tested. + */ + for (sbit=pm->sbitlow; sbit<(1<ngamma_tests; ++i) + { + unsigned int j; + + for (j=0; jngamma_tests; ++j) if (i != j) + { + gamma_transform_test(pm, colour_type, bit_depth, npalette, + pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], + sbit, pm->use_input_precision_sbit, 0 /*scale16*/); + + if (fail(pm)) + return; + } + } + } + } +} + +/* Note that this requires a 16 bit source image but produces 8 bit output, so + * we only need the 16bit write support, but the 16 bit images are only + * generated if DO_16BIT is defined. + */ +#ifdef DO_16BIT +static void perform_gamma_scale16_tests(png_modifier *pm) +{ +# ifndef PNG_MAX_GAMMA_8 +# define PNG_MAX_GAMMA_8 11 +# endif + /* Include the alpha cases here. Note that sbit matches the internal value + * used by the library - otherwise we will get spurious errors from the + * internal sbit style approximation. + * + * The threshold test is here because otherwise the 16 to 8 conversion will + * proceed *without* gamma correction, and the tests above will fail (but not + * by much) - this could be fixed, it only appears with the -g option. + */ + unsigned int i, j; + for (i=0; ingamma_tests; ++i) + { + for (j=0; jngamma_tests; ++j) + { + if (i != j && + fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD) + { + gamma_transform_test(pm, 0, 16, 0, pm->interlace_type, + 1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, + pm->use_input_precision_16to8, 1 /*scale16*/); + + if (fail(pm)) + return; + + gamma_transform_test(pm, 2, 16, 0, pm->interlace_type, + 1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, + pm->use_input_precision_16to8, 1 /*scale16*/); + + if (fail(pm)) + return; + + gamma_transform_test(pm, 4, 16, 0, pm->interlace_type, + 1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, + pm->use_input_precision_16to8, 1 /*scale16*/); + + if (fail(pm)) + return; + + gamma_transform_test(pm, 6, 16, 0, pm->interlace_type, + 1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8, + pm->use_input_precision_16to8, 1 /*scale16*/); + + if (fail(pm)) + return; + } + } + } +} +#endif /* 16 to 8 bit conversion */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +static void gamma_composition_test(png_modifier *pm, + PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth, + PNG_CONST int palette_number, + PNG_CONST int interlace_type, PNG_CONST double file_gamma, + PNG_CONST double screen_gamma, + PNG_CONST int use_input_precision, PNG_CONST int do_background, + PNG_CONST int expand_16) +{ + size_t pos = 0; + png_const_charp base; + double bg; + char name[128]; + png_color_16 background; + + /* Make up a name and get an appropriate background gamma value. */ + switch (do_background) + { + default: + base = ""; + bg = 4; /* should not be used */ + break; + case PNG_BACKGROUND_GAMMA_SCREEN: + base = " bckg(Screen):"; + bg = 1/screen_gamma; + break; + case PNG_BACKGROUND_GAMMA_FILE: + base = " bckg(File):"; + bg = file_gamma; + break; + case PNG_BACKGROUND_GAMMA_UNIQUE: + base = " bckg(Unique):"; + /* This tests the handling of a unique value, the math is such that the + * value tends to be <1, but is neither screen nor file (even if they + * match!) + */ + bg = (file_gamma + screen_gamma) / 3; + break; +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + case ALPHA_MODE_OFFSET + PNG_ALPHA_PNG: + base = " alpha(PNG)"; + bg = 4; /* should not be used */ + break; + case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: + base = " alpha(Porter-Duff)"; + bg = 4; /* should not be used */ + break; + case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: + base = " alpha(Optimized)"; + bg = 4; /* should not be used */ + break; + case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: + base = " alpha(Broken)"; + bg = 4; /* should not be used */ + break; +#endif + } + + /* Use random background values - the background is always presented in the + * output space (8 or 16 bit components). + */ + if (expand_16 || bit_depth == 16) + { + png_uint_32 r = random_32(); + + background.red = (png_uint_16)r; + background.green = (png_uint_16)(r >> 16); + r = random_32(); + background.blue = (png_uint_16)r; + background.gray = (png_uint_16)(r >> 16); + } + + else /* 8 bit colors */ + { + png_uint_32 r = random_32(); + + background.red = (png_byte)r; + background.green = (png_byte)(r >> 8); + background.blue = (png_byte)(r >> 16); + background.gray = (png_byte)(r >> 24); + } + + background.index = 193; /* rgb(193,193,193) to detect errors */ + if (!(colour_type & PNG_COLOR_MASK_COLOR)) + { + /* Grayscale input, we do not convert to RGB (TBD), so we must set the + * background to gray - else libpng seems to fail. + */ + background.red = background.green = background.blue = background.gray; + } + + pos = safecat(name, sizeof name, pos, "gamma "); + pos = safecatd(name, sizeof name, pos, file_gamma, 3); + pos = safecat(name, sizeof name, pos, "->"); + pos = safecatd(name, sizeof name, pos, screen_gamma, 3); + + pos = safecat(name, sizeof name, pos, base); + if (do_background < ALPHA_MODE_OFFSET) + { + /* Include the background color and gamma in the name: */ + pos = safecat(name, sizeof name, pos, "("); + /* This assumes no expand gray->rgb - the current code won't handle that! + */ + if (colour_type & PNG_COLOR_MASK_COLOR) + { + pos = safecatn(name, sizeof name, pos, background.red); + pos = safecat(name, sizeof name, pos, ","); + pos = safecatn(name, sizeof name, pos, background.green); + pos = safecat(name, sizeof name, pos, ","); + pos = safecatn(name, sizeof name, pos, background.blue); + } + else + pos = safecatn(name, sizeof name, pos, background.gray); + pos = safecat(name, sizeof name, pos, ")^"); + pos = safecatd(name, sizeof name, pos, bg, 3); + } + + gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type, + file_gamma, screen_gamma, 0/*sBIT*/, 0, name, use_input_precision, + 0/*strip 16*/, expand_16, do_background, &background, bg); +} + + +static void +perform_gamma_composition_tests(png_modifier *pm, int do_background, + int expand_16) +{ + png_byte colour_type = 0; + png_byte bit_depth = 0; + unsigned int palette_number = 0; + + /* Skip the non-alpha cases - there is no setting of a transparency colour at + * present. + */ + while (next_format(&colour_type, &bit_depth, &palette_number)) + if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0) + { + unsigned int i, j; + + /* Don't skip the i==j case here - it's relevant. */ + for (i=0; ingamma_tests; ++i) for (j=0; jngamma_tests; ++j) + { + gamma_composition_test(pm, colour_type, bit_depth, palette_number, + pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], + pm->use_input_precision, do_background, expand_16); + + if (fail(pm)) + return; + } + } +} +#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ + +static void +init_gamma_errors(png_modifier *pm) +{ + pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0; + pm->error_color_8 = 0; + pm->error_indexed = 0; + pm->error_gray_16 = pm->error_color_16 = 0; +} + +static void +summarize_gamma_errors(png_modifier *pm, png_const_charp who, int low_bit_depth) +{ + if (who) + printf("Gamma correction with %s:\n", who); + + if (low_bit_depth) + { + printf(" 2 bit gray: %.5f\n", pm->error_gray_2); + printf(" 4 bit gray: %.5f\n", pm->error_gray_4); + printf(" 8 bit gray: %.5f\n", pm->error_gray_8); + printf(" 8 bit color: %.5f\n", pm->error_color_8); + printf(" indexed: %.5f\n", pm->error_indexed); + } + +#ifdef DO_16BIT + printf(" 16 bit gray: %.5f\n", pm->error_gray_16); + printf(" 16 bit color: %.5f\n", pm->error_color_16); +#endif +} + +static void +perform_gamma_test(png_modifier *pm, int summary) +{ + /*TODO: remove this*/ + /* Save certain values for the temporary overrides below. */ + unsigned int calculations_use_input_precision = + pm->calculations_use_input_precision; +# ifdef PNG_READ_BACKGROUND_SUPPORTED + double maxout8 = pm->maxout8; +# endif + + /* First some arbitrary no-transform tests: */ + if (!pm->this.speed && pm->test_gamma_threshold) + { + perform_gamma_threshold_tests(pm); + + if (fail(pm)) + return; + } + + /* Now some real transforms. */ + if (pm->test_gamma_transform) + { + init_gamma_errors(pm); + /*TODO: remove this. Necessary because the current libpng + * implementation works in 8 bits: + */ + if (pm->test_gamma_expand16) + pm->calculations_use_input_precision = 1; + perform_gamma_transform_tests(pm); + if (!calculations_use_input_precision) + pm->calculations_use_input_precision = 0; + + if (summary) + { + printf("Gamma correction error summary\n\n"); + printf("The printed value is the maximum error in the pixel values\n"); + printf("calculated by the libpng gamma correction code. The error\n"); + printf("is calculated as the difference between the output pixel\n"); + printf("value (always an integer) and the ideal value from the\n"); + printf("libpng specification (typically not an integer).\n\n"); + + printf("Expect this value to be less than .5 for 8 bit formats,\n"); + printf("less than 1 for formats with fewer than 8 bits and a small\n"); + printf("number (typically less than 5) for the 16 bit formats.\n"); + printf("For performance reasons the value for 16 bit formats\n"); + printf("increases when the image file includes an sBIT chunk.\n\n"); + + summarize_gamma_errors(pm, 0/*who*/, 1); + } + } + + /* The sbit tests produce much larger errors: */ + if (pm->test_gamma_sbit) + { + init_gamma_errors(pm); + perform_gamma_sbit_tests(pm); + + if (summary) + summarize_gamma_errors(pm, "sBIT", pm->sbitlow < 8U); + } + +#ifdef DO_16BIT /* Should be READ_16BIT_SUPPORTED */ + if (pm->test_gamma_scale16) + { + /* The 16 to 8 bit strip operations: */ + init_gamma_errors(pm); + perform_gamma_scale16_tests(pm); + + if (summary) + { + printf("Gamma correction with 16 to 8 bit reduction:\n"); + printf(" 16 bit gray: %.5f\n", pm->error_gray_16); + printf(" 16 bit color: %.5f\n", pm->error_color_16); + } + } +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (pm->test_gamma_background) + { + init_gamma_errors(pm); + + /*TODO: remove this. Necessary because the current libpng + * implementation works in 8 bits: + */ + if (pm->test_gamma_expand16) + { + pm->calculations_use_input_precision = 1; + pm->maxout8 = .499; /* because the 16 bit background is smashed */ + } + perform_gamma_composition_tests(pm, PNG_BACKGROUND_GAMMA_UNIQUE, + pm->test_gamma_expand16); + if (!calculations_use_input_precision) + pm->calculations_use_input_precision = 0; + pm->maxout8 = maxout8; + + if (summary) + summarize_gamma_errors(pm, "background", 1); + } +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if (pm->test_gamma_alpha_mode) + { + int do_background; + + init_gamma_errors(pm); + + /*TODO: remove this. Necessary because the current libpng + * implementation works in 8 bits: + */ + if (pm->test_gamma_expand16) + pm->calculations_use_input_precision = 1; + for (do_background = ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD; + do_background <= ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN && !fail(pm); + ++do_background) + perform_gamma_composition_tests(pm, do_background, + pm->test_gamma_expand16); + if (!calculations_use_input_precision) + pm->calculations_use_input_precision = 0; + + if (summary) + summarize_gamma_errors(pm, "alpha mode", 1); + } +#endif +} +#endif /* PNG_READ_GAMMA_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ + +/* INTERLACE MACRO VALIDATION */ +/* This is copied verbatim from the specification, it is simply the pass + * number in which each pixel in each 8x8 tile appears. The array must + * be indexed adam7[y][x] and notice that the pass numbers are based at + * 1, not 0 - the base libpng uses. + */ +static PNG_CONST +png_byte adam7[8][8] = +{ + { 1,6,4,6,2,6,4,6 }, + { 7,7,7,7,7,7,7,7 }, + { 5,6,5,6,5,6,5,6 }, + { 7,7,7,7,7,7,7,7 }, + { 3,6,4,6,3,6,4,6 }, + { 7,7,7,7,7,7,7,7 }, + { 5,6,5,6,5,6,5,6 }, + { 7,7,7,7,7,7,7,7 } +}; + +/* This routine validates all the interlace support macros in png.h for + * a variety of valid PNG widths and heights. It uses a number of similarly + * named internal routines that feed off the above array. + */ +static png_uint_32 +png_pass_start_row(int pass) +{ + int x, y; + ++pass; + for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) + return y; + return 0xf; +} + +static png_uint_32 +png_pass_start_col(int pass) +{ + int x, y; + ++pass; + for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) + return x; + return 0xf; +} + +static int +png_pass_row_shift(int pass) +{ + int x, y, base=(-1), inc=8; + ++pass; + for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) + { + if (base == (-1)) + base = y; + else if (base == y) + {} + else if (inc == y-base) + base=y; + else if (inc == 8) + inc = y-base, base=y; + else if (inc != y-base) + return 0xff; /* error - more than one 'inc' value! */ + } + + if (base == (-1)) return 0xfe; /* error - no row in pass! */ + + /* The shift is always 1, 2 or 3 - no pass has all the rows! */ + switch (inc) + { +case 2: return 1; +case 4: return 2; +case 8: return 3; +default: break; + } + + /* error - unrecognized 'inc' */ + return (inc << 8) + 0xfd; +} + +static int +png_pass_col_shift(int pass) +{ + int x, y, base=(-1), inc=8; + ++pass; + for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) + { + if (base == (-1)) + base = x; + else if (base == x) + {} + else if (inc == x-base) + base=x; + else if (inc == 8) + inc = x-base, base=x; + else if (inc != x-base) + return 0xff; /* error - more than one 'inc' value! */ + } + + if (base == (-1)) return 0xfe; /* error - no row in pass! */ + + /* The shift is always 1, 2 or 3 - no pass has all the rows! */ + switch (inc) + { +case 1: return 0; /* pass 7 has all the columns */ +case 2: return 1; +case 4: return 2; +case 8: return 3; +default: break; + } + + /* error - unrecognized 'inc' */ + return (inc << 8) + 0xfd; +} + +static png_uint_32 +png_row_from_pass_row(png_uint_32 yIn, int pass) +{ + /* By examination of the array: */ + switch (pass) + { +case 0: return yIn * 8; +case 1: return yIn * 8; +case 2: return yIn * 8 + 4; +case 3: return yIn * 4; +case 4: return yIn * 4 + 2; +case 5: return yIn * 2; +case 6: return yIn * 2 + 1; +default: break; + } + + return 0xff; /* bad pass number */ +} + +static png_uint_32 +png_col_from_pass_col(png_uint_32 xIn, int pass) +{ + /* By examination of the array: */ + switch (pass) + { +case 0: return xIn * 8; +case 1: return xIn * 8 + 4; +case 2: return xIn * 4; +case 3: return xIn * 4 + 2; +case 4: return xIn * 2; +case 5: return xIn * 2 + 1; +case 6: return xIn; +default: break; + } + + return 0xff; /* bad pass number */ +} + +static int +png_row_in_interlace_pass(png_uint_32 y, int pass) +{ + /* Is row 'y' in pass 'pass'? */ + int x; + y &= 7; + ++pass; + for (x=0; x<8; ++x) if (adam7[y][x] == pass) + return 1; + + return 0; +} + +static int +png_col_in_interlace_pass(png_uint_32 x, int pass) +{ + /* Is column 'x' in pass 'pass'? */ + int y; + x &= 7; + ++pass; + for (y=0; y<8; ++y) if (adam7[y][x] == pass) + return 1; + + return 0; +} + +static png_uint_32 +png_pass_rows(png_uint_32 height, int pass) +{ + png_uint_32 tiles = height>>3; + png_uint_32 rows = 0; + unsigned int x, y; + + height &= 7; + ++pass; + for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) + { + rows += tiles; + if (y < height) ++rows; + break; /* i.e. break the 'x', column, loop. */ + } + + return rows; +} + +static png_uint_32 +png_pass_cols(png_uint_32 width, int pass) +{ + png_uint_32 tiles = width>>3; + png_uint_32 cols = 0; + unsigned int x, y; + + width &= 7; + ++pass; + for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) + { + cols += tiles; + if (x < width) ++cols; + break; /* i.e. break the 'y', row, loop. */ + } + + return cols; +} + +static void +perform_interlace_macro_validation(void) +{ + /* The macros to validate, first those that depend only on pass: + * + * PNG_PASS_START_ROW(pass) + * PNG_PASS_START_COL(pass) + * PNG_PASS_ROW_SHIFT(pass) + * PNG_PASS_COL_SHIFT(pass) + */ + int pass; + + for (pass=0; pass<7; ++pass) + { + png_uint_32 m, f, v; + + m = PNG_PASS_START_ROW(pass); + f = png_pass_start_row(pass); + if (m != f) + { + fprintf(stderr, "PNG_PASS_START_ROW(%d) = %u != %x\n", pass, m, f); + exit(1); + } + + m = PNG_PASS_START_COL(pass); + f = png_pass_start_col(pass); + if (m != f) + { + fprintf(stderr, "PNG_PASS_START_COL(%d) = %u != %x\n", pass, m, f); + exit(1); + } + + m = PNG_PASS_ROW_SHIFT(pass); + f = png_pass_row_shift(pass); + if (m != f) + { + fprintf(stderr, "PNG_PASS_ROW_SHIFT(%d) = %u != %x\n", pass, m, f); + exit(1); + } + + m = PNG_PASS_COL_SHIFT(pass); + f = png_pass_col_shift(pass); + if (m != f) + { + fprintf(stderr, "PNG_PASS_COL_SHIFT(%d) = %u != %x\n", pass, m, f); + exit(1); + } + + /* Macros that depend on the image or sub-image height too: + * + * PNG_PASS_ROWS(height, pass) + * PNG_PASS_COLS(width, pass) + * PNG_ROW_FROM_PASS_ROW(yIn, pass) + * PNG_COL_FROM_PASS_COL(xIn, pass) + * PNG_ROW_IN_INTERLACE_PASS(y, pass) + * PNG_COL_IN_INTERLACE_PASS(x, pass) + */ + for (v=0;;) + { + /* First the base 0 stuff: */ + m = PNG_ROW_FROM_PASS_ROW(v, pass); + f = png_row_from_pass_row(v, pass); + if (m != f) + { + fprintf(stderr, "PNG_ROW_FROM_PASS_ROW(%u, %d) = %u != %x\n", + v, pass, m, f); + exit(1); + } + + m = PNG_COL_FROM_PASS_COL(v, pass); + f = png_col_from_pass_col(v, pass); + if (m != f) + { + fprintf(stderr, "PNG_COL_FROM_PASS_COL(%u, %d) = %u != %x\n", + v, pass, m, f); + exit(1); + } + + m = PNG_ROW_IN_INTERLACE_PASS(v, pass); + f = png_row_in_interlace_pass(v, pass); + if (m != f) + { + fprintf(stderr, "PNG_ROW_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", + v, pass, m, f); + exit(1); + } + + m = PNG_COL_IN_INTERLACE_PASS(v, pass); + f = png_col_in_interlace_pass(v, pass); + if (m != f) + { + fprintf(stderr, "PNG_COL_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", + v, pass, m, f); + exit(1); + } + + /* Then the base 1 stuff: */ + ++v; + m = PNG_PASS_ROWS(v, pass); + f = png_pass_rows(v, pass); + if (m != f) + { + fprintf(stderr, "PNG_PASS_ROWS(%u, %d) = %u != %x\n", + v, pass, m, f); + exit(1); + } + + m = PNG_PASS_COLS(v, pass); + f = png_pass_cols(v, pass); + if (m != f) + { + fprintf(stderr, "PNG_PASS_COLS(%u, %d) = %u != %x\n", + v, pass, m, f); + exit(1); + } + + /* Move to the next v - the stepping algorithm starts skipping + * values above 1024. + */ + if (v > 1024) + { + if (v == PNG_UINT_31_MAX) + break; + + v = (v << 1) ^ v; + if (v >= PNG_UINT_31_MAX) + v = PNG_UINT_31_MAX-1; + } + } + } +} + +/* Test color encodings. These values are back-calculated from the published + * chromaticities. The values are accurate to about 14 decimal places; 15 are + * given. These values are much more accurate than the ones given in the spec, + * which typically don't exceed 4 decimal places. This allows testing of the + * libpng code to its theoretical accuracy of 4 decimal places. (If pngvalid + * used the published errors the 'slack' permitted would have to be +/-.5E-4 or + * more.) + * + * The png_modifier code assumes that encodings[0] is sRGB and treats it + * specially: do not change the first entry in this list! + */ +static PNG_CONST color_encoding test_encodings[] = +{ +/* sRGB: must be first in this list! */ +/*gamma:*/ { 1/2.2, +/*red: */ { 0.412390799265959, 0.212639005871510, 0.019330818715592 }, +/*green:*/ { 0.357584339383878, 0.715168678767756, 0.119194779794626 }, +/*blue: */ { 0.180480788401834, 0.072192315360734, 0.950532152249660} }, +/* Kodak ProPhoto (wide gamut) */ +/*gamma:*/ { 1/1.6 /*approximate: uses 1.8 power law compared to sRGB 2.4*/, +/*red: */ { 0.797760489672303, 0.288071128229293, 0.000000000000000 }, +/*green:*/ { 0.135185837175740, 0.711843217810102, 0.000000000000000 }, +/*blue: */ { 0.031349349581525, 0.000085653960605, 0.825104602510460} }, +/* Adobe RGB (1998) */ +/*gamma:*/ { 1/(2+51./256), +/*red: */ { 0.576669042910131, 0.297344975250536, 0.027031361386412 }, +/*green:*/ { 0.185558237906546, 0.627363566255466, 0.070688852535827 }, +/*blue: */ { 0.188228646234995, 0.075291458493998, 0.991337536837639} }, +/* Adobe Wide Gamut RGB */ +/*gamma:*/ { 1/(2+51./256), +/*red: */ { 0.716500716779386, 0.258728243040113, 0.000000000000000 }, +/*green:*/ { 0.101020574397477, 0.724682314948566, 0.051211818965388 }, +/*blue: */ { 0.146774385252705, 0.016589442011321, 0.773892783545073} }, +}; + +/* signal handler + * + * This attempts to trap signals and escape without crashing. It needs a + * context pointer so that it can throw an exception (call longjmp) to recover + * from the condition; this is handled by making the png_modifier used by 'main' + * into a global variable. + */ +static png_modifier pm; + +static void signal_handler(int signum) +{ + + size_t pos = 0; + char msg[64]; + + pos = safecat(msg, sizeof msg, pos, "caught signal: "); + + switch (signum) + { + case SIGABRT: + pos = safecat(msg, sizeof msg, pos, "abort"); + break; + + case SIGFPE: + pos = safecat(msg, sizeof msg, pos, "floating point exception"); + break; + + case SIGILL: + pos = safecat(msg, sizeof msg, pos, "illegal instruction"); + break; + + case SIGINT: + pos = safecat(msg, sizeof msg, pos, "interrupt"); + break; + + case SIGSEGV: + pos = safecat(msg, sizeof msg, pos, "invalid memory access"); + break; + + case SIGTERM: + pos = safecat(msg, sizeof msg, pos, "termination request"); + break; + + default: + pos = safecat(msg, sizeof msg, pos, "unknown "); + pos = safecatn(msg, sizeof msg, pos, signum); + break; + } + + store_log(&pm.this, NULL/*png_structp*/, msg, 1/*error*/); + + /* And finally throw an exception so we can keep going, unless this is + * SIGTERM in which case stop now. + */ + if (signum != SIGTERM) + { + struct exception_context *the_exception_context = + &pm.this.exception_context; + + Throw &pm.this; + } + + else + exit(1); +} + +/* main program */ +int main(int argc, char **argv) +{ + volatile int summary = 1; /* Print the error summary at the end */ + volatile int memstats = 0; /* Print memory statistics at the end */ + + /* Create the given output file on success: */ + PNG_CONST char *volatile touch = NULL; + + /* This is an array of standard gamma values (believe it or not I've seen + * every one of these mentioned somewhere.) + * + * In the following list the most useful values are first! + */ + static double + gammas[]={2.2, 1.0, 2.2/1.45, 1.8, 1.5, 2.4, 2.5, 2.62, 2.9}; + + /* This records the command and arguments: */ + size_t cp = 0; + char command[1024]; + + anon_context(&pm.this); + + /* Add appropriate signal handlers, just the ANSI specified ones: */ + signal(SIGABRT, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGTERM, signal_handler); + +#ifdef HAVE_FEENABLEEXCEPT + /* Only required to enable FP exceptions on platforms where they start off + * disabled; this is not necessary but if it is not done pngvalid will likely + * end up ignoring FP conditions that other platforms fault. + */ + feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + + modifier_init(&pm); + + /* Preallocate the image buffer, because we know how big it needs to be, + * note that, for testing purposes, it is deliberately mis-aligned by tag + * bytes either side. All rows have an additional five bytes of padding for + * overwrite checking. + */ + store_ensure_image(&pm.this, NULL, 2, TRANSFORM_ROWMAX, TRANSFORM_HEIGHTMAX); + + /* Don't give argv[0], it's normally some horrible libtool string: */ + cp = safecat(command, sizeof command, cp, "pngvalid"); + + /* Default to error on warning: */ + pm.this.treat_warnings_as_errors = 1; + + /* Store the test gammas */ + pm.gammas = gammas; + pm.ngammas = (sizeof gammas) / (sizeof gammas[0]); + pm.ngamma_tests = 0; /* default to off */ + + /* And the test encodings */ + pm.encodings = test_encodings; + pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]); + + pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */ + /* The following allows results to pass if they correspond to anything in the + * transformed range [input-.5,input+.5]; this is is required because of the + * way libpng treates the 16_TO_8 flag when building the gamma tables. + * + * TODO: review this + */ + pm.use_input_precision_16to8 = 1U; + + /* Some default values (set the behavior for 'make check' here). + * These values simply control the maximum error permitted in the gamma + * transformations. The practial limits for human perception are described + * below (the setting for maxpc16), however for 8 bit encodings it isn't + * possible to meet the accepted capabilities of human vision - i.e. 8 bit + * images can never be good enough, regardless of encoding. + */ + pm.maxout8 = .1; /* Arithmetic error in *encoded* value */ + pm.maxabs8 = .00005; /* 1/20000 */ + pm.maxcalc8 = .004; /* +/-1 in 8 bits for compose errors */ + pm.maxpc8 = .499; /* I.e., .499% fractional error */ + pm.maxout16 = .499; /* Error in *encoded* value */ + pm.maxabs16 = .00005;/* 1/20000 */ + pm.maxcalc16 =.000015;/* +/-1 in 16 bits for compose errors */ + + /* NOTE: this is a reasonable perceptual limit. We assume that humans can + * perceive light level differences of 1% over a 100:1 range, so we need to + * maintain 1 in 10000 accuracy (in linear light space), which is what the + * following guarantees. It also allows significantly higher errors at + * higher 16 bit values, which is important for performance. The actual + * maximum 16 bit error is about +/-1.9 in the fixed point implementation but + * this is only allowed for values >38149 by the following: + */ + pm.maxpc16 = .005; /* I.e., 1/200% - 1/20000 */ + + /* Now parse the command line options. */ + while (--argc >= 1) + { + int catmore = 0; /* Set if the argument has an argument. */ + + /* Record each argument for posterity: */ + cp = safecat(command, sizeof command, cp, " "); + cp = safecat(command, sizeof command, cp, *++argv); + + if (strcmp(*argv, "-v") == 0) + pm.this.verbose = 1; + + else if (strcmp(*argv, "-l") == 0) + pm.log = 1; + + else if (strcmp(*argv, "-q") == 0) + summary = pm.this.verbose = pm.log = 0; + + else if (strcmp(*argv, "-w") == 0) + pm.this.treat_warnings_as_errors = 0; + + else if (strcmp(*argv, "--speed") == 0) + pm.this.speed = 1, pm.ngamma_tests = pm.ngammas, pm.test_standard = 0, + summary = 0; + + else if (strcmp(*argv, "--memory") == 0) + memstats = 1; + + else if (strcmp(*argv, "--size") == 0) + pm.test_size = 1; + + else if (strcmp(*argv, "--nosize") == 0) + pm.test_size = 0; + + else if (strcmp(*argv, "--standard") == 0) + pm.test_standard = 1; + + else if (strcmp(*argv, "--nostandard") == 0) + pm.test_standard = 0; + + else if (strcmp(*argv, "--transform") == 0) + pm.test_transform = 1; + + else if (strcmp(*argv, "--notransform") == 0) + pm.test_transform = 0; + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + else if (strncmp(*argv, "--transform-disable=", + sizeof "--transform-disable") == 0) + { + pm.test_transform = 1; + transform_disable(*argv + sizeof "--transform-disable"); + } + + else if (strncmp(*argv, "--transform-enable=", + sizeof "--transform-enable") == 0) + { + pm.test_transform = 1; + transform_enable(*argv + sizeof "--transform-enable"); + } +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + + else if (strcmp(*argv, "--gamma") == 0) + { + /* Just do two gamma tests here (2.2 and linear) for speed: */ + pm.ngamma_tests = 2U; + pm.test_gamma_threshold = 1; + pm.test_gamma_transform = 1; + pm.test_gamma_sbit = 1; + pm.test_gamma_scale16 = 1; + pm.test_gamma_background = 1; + pm.test_gamma_alpha_mode = 1; + } + + else if (strcmp(*argv, "--nogamma") == 0) + pm.ngamma_tests = 0; + + else if (strcmp(*argv, "--gamma-threshold") == 0) + pm.ngamma_tests = 2U, pm.test_gamma_threshold = 1; + + else if (strcmp(*argv, "--nogamma-threshold") == 0) + pm.test_gamma_threshold = 0; + + else if (strcmp(*argv, "--gamma-transform") == 0) + pm.ngamma_tests = 2U, pm.test_gamma_transform = 1; + + else if (strcmp(*argv, "--nogamma-transform") == 0) + pm.test_gamma_transform = 0; + + else if (strcmp(*argv, "--gamma-sbit") == 0) + pm.ngamma_tests = 2U, pm.test_gamma_sbit = 1; + + else if (strcmp(*argv, "--nogamma-sbit") == 0) + pm.test_gamma_sbit = 0; + + else if (strcmp(*argv, "--gamma-16-to-8") == 0) + pm.ngamma_tests = 2U, pm.test_gamma_scale16 = 1; + + else if (strcmp(*argv, "--nogamma-16-to-8") == 0) + pm.test_gamma_scale16 = 0; + + else if (strcmp(*argv, "--gamma-background") == 0) + pm.ngamma_tests = 2U, pm.test_gamma_background = 1; + + else if (strcmp(*argv, "--nogamma-background") == 0) + pm.test_gamma_background = 0; + + else if (strcmp(*argv, "--gamma-alpha-mode") == 0) + pm.ngamma_tests = 2U, pm.test_gamma_alpha_mode = 1; + + else if (strcmp(*argv, "--nogamma-alpha-mode") == 0) + pm.test_gamma_alpha_mode = 0; + + else if (strcmp(*argv, "--expand16") == 0) + pm.test_gamma_expand16 = 1; + + else if (strcmp(*argv, "--noexpand16") == 0) + pm.test_gamma_expand16 = 0; + + else if (strcmp(*argv, "--more-gammas") == 0) + pm.ngamma_tests = 3U; + + else if (strcmp(*argv, "--all-gammas") == 0) + pm.ngamma_tests = pm.ngammas; + + else if (strcmp(*argv, "--progressive-read") == 0) + pm.this.progressive = 1; + + else if (strcmp(*argv, "--use-update-info") == 0) + ++pm.use_update_info; /* Can call multiple times */ + + else if (strcmp(*argv, "--interlace") == 0) + pm.interlace_type = PNG_INTERLACE_ADAM7; + + else if (strcmp(*argv, "--use-input-precision") == 0) + pm.use_input_precision = 1; + + else if (strcmp(*argv, "--calculations-use-input-precision") == 0) + pm.calculations_use_input_precision = 1; + + else if (strcmp(*argv, "--assume-16-bit-calculations") == 0) + pm.assume_16_bit_calculations = 1; + + else if (strcmp(*argv, "--calculations-follow-bit-depth") == 0) + pm.calculations_use_input_precision = + pm.assume_16_bit_calculations = 0; + + else if (strcmp(*argv, "--exhaustive") == 0) + pm.test_exhaustive = 1; + + else if (argc > 1 && strcmp(*argv, "--sbitlow") == 0) + --argc, pm.sbitlow = (png_byte)atoi(*++argv), catmore = 1; + + else if (argc > 1 && strcmp(*argv, "--touch") == 0) + --argc, touch = *++argv, catmore = 1; + + else if (argc > 1 && strncmp(*argv, "--max", 5) == 0) + { + --argc; + + if (strcmp(5+*argv, "abs8") == 0) + pm.maxabs8 = atof(*++argv); + + else if (strcmp(5+*argv, "abs16") == 0) + pm.maxabs16 = atof(*++argv); + + else if (strcmp(5+*argv, "calc8") == 0) + pm.maxcalc8 = atof(*++argv); + + else if (strcmp(5+*argv, "calc16") == 0) + pm.maxcalc16 = atof(*++argv); + + else if (strcmp(5+*argv, "out8") == 0) + pm.maxout8 = atof(*++argv); + + else if (strcmp(5+*argv, "out16") == 0) + pm.maxout16 = atof(*++argv); + + else if (strcmp(5+*argv, "pc8") == 0) + pm.maxpc8 = atof(*++argv); + + else if (strcmp(5+*argv, "pc16") == 0) + pm.maxpc16 = atof(*++argv); + + else + { + fprintf(stderr, "pngvalid: %s: unknown 'max' option\n", *argv); + exit(1); + } + + catmore = 1; + } + + else if (strcmp(*argv, "--log8") == 0) + --argc, pm.log8 = atof(*++argv), catmore = 1; + + else if (strcmp(*argv, "--log16") == 0) + --argc, pm.log16 = atof(*++argv), catmore = 1; + + else + { + fprintf(stderr, "pngvalid: %s: unknown argument\n", *argv); + exit(1); + } + + if (catmore) /* consumed an extra *argv */ + { + cp = safecat(command, sizeof command, cp, " "); + cp = safecat(command, sizeof command, cp, *argv); + } + } + + /* If pngvalid is run with no arguments default to a reasonable set of the + * tests. + */ + if (pm.test_standard == 0 && pm.test_size == 0 && pm.test_transform == 0 && + pm.ngamma_tests == 0) + { + /* Make this do all the tests done in the test shell scripts with the same + * parameters, where possible. The limitation is that all the progressive + * read and interlace stuff has to be done in separate runs, so only the + * basic 'standard' and 'size' tests are done. + */ + pm.test_standard = 1; + pm.test_size = 1; + pm.test_transform = 1; + pm.ngamma_tests = 2U; + } + + if (pm.ngamma_tests > 0 && + pm.test_gamma_threshold == 0 && pm.test_gamma_transform == 0 && + pm.test_gamma_sbit == 0 && pm.test_gamma_scale16 == 0 && + pm.test_gamma_background == 0 && pm.test_gamma_alpha_mode == 0) + { + pm.test_gamma_threshold = 1; + pm.test_gamma_transform = 1; + pm.test_gamma_sbit = 1; + pm.test_gamma_scale16 = 1; + pm.test_gamma_background = 1; + pm.test_gamma_alpha_mode = 1; + } + + else if (pm.ngamma_tests == 0) + { + /* Nothing to test so turn everything off: */ + pm.test_gamma_threshold = 0; + pm.test_gamma_transform = 0; + pm.test_gamma_sbit = 0; + pm.test_gamma_scale16 = 0; + pm.test_gamma_background = 0; + pm.test_gamma_alpha_mode = 0; + } + + Try + { + /* Make useful base images */ + make_transform_images(&pm.this); + + /* Perform the standard and gamma tests. */ + if (pm.test_standard) + { + perform_interlace_macro_validation(); + perform_formatting_test(&pm.this); +# ifdef PNG_READ_SUPPORTED + perform_standard_test(&pm); +# endif + perform_error_test(&pm); + } + + /* Various oddly sized images: */ + if (pm.test_size) + { + make_size_images(&pm.this); +# ifdef PNG_READ_SUPPORTED + perform_size_test(&pm); +# endif + } + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + /* Combinatorial transforms: */ + if (pm.test_transform) + perform_transform_test(&pm); +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +#ifdef PNG_READ_GAMMA_SUPPORTED + if (pm.ngamma_tests > 0) + perform_gamma_test(&pm, summary); +#endif + } + + Catch_anonymous + { + fprintf(stderr, "pngvalid: test aborted (probably failed in cleanup)\n"); + if (!pm.this.verbose) + { + if (pm.this.error[0] != 0) + fprintf(stderr, "pngvalid: first error: %s\n", pm.this.error); + + fprintf(stderr, "pngvalid: run with -v to see what happened\n"); + } + exit(1); + } + + if (summary) + { + printf("%s: %s (%s point arithmetic)\n", + (pm.this.nerrors || (pm.this.treat_warnings_as_errors && + pm.this.nwarnings)) ? "FAIL" : "PASS", + command, +#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || PNG_LIBPNG_VER < 10500 + "floating" +#else + "fixed" +#endif + ); + } + + if (memstats) + { + printf("Allocated memory statistics (in bytes):\n" + "\tread %lu maximum single, %lu peak, %lu total\n" + "\twrite %lu maximum single, %lu peak, %lu total\n", + (unsigned long)pm.this.read_memory_pool.max_max, + (unsigned long)pm.this.read_memory_pool.max_limit, + (unsigned long)pm.this.read_memory_pool.max_total, + (unsigned long)pm.this.write_memory_pool.max_max, + (unsigned long)pm.this.write_memory_pool.max_limit, + (unsigned long)pm.this.write_memory_pool.max_total); + } + + /* Do this here to provoke memory corruption errors in memory not directly + * allocated by libpng - not a complete test, but better than nothing. + */ + store_delete(&pm.this); + + /* Error exit if there are any errors, and maybe if there are any + * warnings. + */ + if (pm.this.nerrors || (pm.this.treat_warnings_as_errors && + pm.this.nwarnings)) + { + if (!pm.this.verbose) + fprintf(stderr, "pngvalid: %s\n", pm.this.error); + + fprintf(stderr, "pngvalid: %d errors, %d warnings\n", pm.this.nerrors, + pm.this.nwarnings); + + exit(1); + } + + /* Success case. */ + if (touch != NULL) + { + FILE *fsuccess = fopen(touch, "wt"); + + if (fsuccess != NULL) + { + int error = 0; + fprintf(fsuccess, "PNG validation succeeded\n"); + fflush(fsuccess); + error = ferror(fsuccess); + + if (fclose(fsuccess) || error) + { + fprintf(stderr, "%s: write failed\n", touch); + exit(1); + } + } + + else + { + fprintf(stderr, "%s: open failed\n", touch); + exit(1); + } + } + + return 0; +} +#else /* write not supported */ +int main(void) +{ + fprintf(stderr, "pngvalid: no write support in libpng, all tests skipped\n"); + /* So the test is skipped: */ + return 77; +} +#endif diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/readpng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/readpng.c new file mode 100644 index 00000000000..7ba46d0b96b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/readpng.c @@ -0,0 +1,104 @@ +/* readpng.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Load an arbitrary number of PNG files (from the command line, or, if there + * are no arguments on the command line, from stdin) then run a time test by + * reading each file by row. The test does nothing with the read result and + * does no transforms. The only output is a time as a floating point number of + * seconds with 9 decimal digits. + */ +#include +#include +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +static int +read_png(FILE *fp) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); + png_infop info_ptr = NULL; + png_bytep row = NULL, display = NULL; + + if (png_ptr == NULL) + return 0; + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (row != NULL) free(row); + if (display != NULL) free(display); + return 0; + } + + png_init_io(png_ptr, fp); + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); + + png_read_info(png_ptr, info_ptr); + + { + png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + row = malloc(rowbytes); + display = malloc(rowbytes); + + if (row == NULL || display == NULL) + png_error(png_ptr, "OOM allocating row buffers"); + + { + png_uint_32 height = png_get_image_height(png_ptr, info_ptr); + int passes = png_set_interlace_handling(png_ptr); + int pass; + + png_start_read_image(png_ptr); + + for (pass = 0; pass < passes; ++pass) + { + png_uint_32 y = height; + + /* NOTE: this trashes the row each time; interlace handling won't + * work, but this avoids memory thrashing for speed testing. + */ + while (y-- > 0) + png_read_row(png_ptr, row, display); + } + } + } + + /* Make sure to read to the end of the file: */ + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + free(row); + free(display); + return 1; +} + +int +main(void) +{ + /* Exit code 0 on success. */ + return !read_png(stdin); +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/tarith.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/tarith.c new file mode 100644 index 00000000000..cdb00dbf7e7 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/tarith.c @@ -0,0 +1,999 @@ + +/* tarith.c + * + * Copyright (c) 2011-2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Test internal arithmetic functions of libpng. + * + * This code must be linked against a math library (-lm), but does not require + * libpng or zlib to work. Because it includes the complete source of 'png.c' + * it tests the code with whatever compiler options are used to build it. + * Changing these options can substantially change the errors in the + * calculations that the compiler chooses! + */ +#define _POSIX_SOURCE 1 +#define _ISOC99_SOURCE 1 + +/* Obtain a copy of the code to be tested (plus other things), disabling + * stuff that is not required. + */ +#include +#include +#include +#include +#include + +#include "../../pngpriv.h" + +#define png_error png_warning + +void png_warning(png_const_structrp png_ptr, png_const_charp msg) +{ + fprintf(stderr, "validation: %s\n", msg); +} + +#define png_fixed_error png_fixed_warning + +void png_fixed_warning(png_const_structrp png_ptr, png_const_charp msg) +{ + fprintf(stderr, "overflow in: %s\n", msg); +} + +#define png_set_error_fn(pp, ep, efp, wfp) ((void)0) +#define png_malloc(pp, s) malloc(s) +#define png_malloc_warn(pp, s) malloc(s) +#define png_malloc_base(pp, s) malloc(s) +#define png_calloc(pp, s) calloc(1, (s)) +#define png_free(pp, s) free(s) + +#define png_safecat(b, sb, pos, str) (pos) +#define png_format_number(start, end, format, number) (start) + +#define crc32(crc, pp, s) (crc) +#define inflateReset(zs) Z_OK + +#define png_create_struct(type) (0) +#define png_destroy_struct(pp) ((void)0) +#define png_create_struct_2(type, m, mm) (0) +#define png_destroy_struct_2(pp, f, mm) ((void)0) + +#undef PNG_SIMPLIFIED_READ_SUPPORTED +#undef PNG_SIMPLIFIED_WRITE_SUPPORTED +#undef PNG_USER_MEM_SUPPORTED + +#include "../../png.c" + +/* Validate ASCII to fp routines. */ +static int verbose = 0; + +int validation_ascii_to_fp(int count, int argc, char **argv) +{ + int showall = 0; + double max_error=2; /* As a percentage error-in-last-digit/.5 */ + double max_error_abs=17; /* Used when precision is DBL_DIG */ + double max = 0; + double max_abs = 0; + double test = 0; /* Important to test this. */ + int precision = 5; + int nonfinite = 0; + int finite = 0; + int ok = 0; + int failcount = 0; + int minorarith = 0; + + while (--argc > 0) + if (strcmp(*++argv, "-a") == 0) + showall = 1; + else if (strcmp(*argv, "-e") == 0 && argc > 0) + { + --argc; + max_error = atof(*++argv); + } + else if (strcmp(*argv, "-E") == 0 && argc > 0) + { + --argc; + max_error_abs = atof(*++argv); + } + else + { + fprintf(stderr, "unknown argument %s\n", *argv); + return 1; + } + + do + { + png_size_t index; + int state, failed = 0; + char buffer[64]; + + if (isfinite(test)) + ++finite; + else + ++nonfinite; + + if (verbose) + fprintf(stderr, "%.*g %d\n", DBL_DIG, test, precision); + + /* Check for overflow in the buffer by setting a marker. */ + memset(buffer, 71, sizeof buffer); + + png_ascii_from_fp(0, buffer, precision+10, test, precision); + + /* Allow for a three digit exponent, this stuff will fail if + * the exponent is bigger than this! + */ + if (buffer[precision+7] != 71) + { + fprintf(stderr, "%g[%d] -> '%s'[%lu] buffer overflow\n", test, + precision, buffer, (unsigned long)strlen(buffer)); + failed = 1; + } + + /* Following are used for the number parser below and must be + * initialized to zero. + */ + state = 0; + index = 0; + if (!isfinite(test)) + { + /* Expect 'inf' */ + if (test >= 0 && strcmp(buffer, "inf") || + test < 0 && strcmp(buffer, "-inf")) + { + fprintf(stderr, "%g[%d] -> '%s' but expected 'inf'\n", test, + precision, buffer); + failed = 1; + } + } + else if (!png_check_fp_number(buffer, precision+10, &state, &index) || + buffer[index] != 0) + { + fprintf(stderr, "%g[%d] -> '%s' but has bad format ('%c')\n", test, + precision, buffer, buffer[index]); + failed = 1; + } + else if (PNG_FP_IS_NEGATIVE(state) && !(test < 0)) + { + fprintf(stderr, "%g[%d] -> '%s' but negative value not so reported\n", + test, precision, buffer); + failed = 1; + assert(!PNG_FP_IS_ZERO(state)); + assert(!PNG_FP_IS_POSITIVE(state)); + } + else if (PNG_FP_IS_ZERO(state) && !(test == 0)) + { + fprintf(stderr, "%g[%d] -> '%s' but zero value not so reported\n", + test, precision, buffer); + failed = 1; + assert(!PNG_FP_IS_NEGATIVE(state)); + assert(!PNG_FP_IS_POSITIVE(state)); + } + else if (PNG_FP_IS_POSITIVE(state) && !(test > 0)) + { + fprintf(stderr, "%g[%d] -> '%s' but postive value not so reported\n", + test, precision, buffer); + failed = 1; + assert(!PNG_FP_IS_NEGATIVE(state)); + assert(!PNG_FP_IS_ZERO(state)); + } + else + { + /* Check the result against the original. */ + double out = atof(buffer); + double change = fabs((out - test)/test); + double allow = .5/pow(10, + (precision >= DBL_DIG) ? DBL_DIG-1 : precision-1); + + /* NOTE: if you hit this error case are you compiling with gcc + * and -O0? Try -O2 - the errors can accumulate if the FP + * code above is not optimized and may drift outside the .5 in + * DBL_DIG allowed. In any case a small number of errors may + * occur (very small ones - 1 or 2%) because of rounding in the + * calculations, either in the conversion API or in atof. + */ + if (change >= allow && (isfinite(out) || + fabs(test/DBL_MAX) <= 1-allow)) + { + double percent = (precision >= DBL_DIG) ? max_error_abs : max_error; + double allowp = (change-allow)*100/allow; + + if (precision >= DBL_DIG) + { + if (max_abs < allowp) max_abs = allowp; + } + + else + { + if (max < allowp) max = allowp; + } + + if (showall || allowp >= percent) + { + fprintf(stderr, + "%.*g[%d] -> '%s' -> %.*g number changed (%g > %g (%d%%))\n", + DBL_DIG, test, precision, buffer, DBL_DIG, out, change, allow, + (int)round(allowp)); + failed = 1; + } + else + ++minorarith; + } + } + + if (failed) + ++failcount; + else + ++ok; + +skip: + /* Generate a new number and precision. */ + precision = rand(); + if (precision & 1) test = -test; + precision >>= 1; + + /* Generate random numbers. */ + if (test == 0 || !isfinite(test)) + test = precision+1; + else + { + /* Derive the exponent from the previous rand() value. */ + int exponent = precision % (DBL_MAX_EXP - DBL_MIN_EXP) + DBL_MIN_EXP; + int tmp; + test = frexp(test * rand(), &tmp); + test = ldexp(test, exponent); + precision >>= 8; /* arbitrary */ + } + + /* This limits the precision to 32 digits, enough for standard + * IEEE implementations which have at most 15 digits. + */ + precision = (precision & 0x1f) + 1; + } + while (--count); + + printf("Tested %d finite values, %d non-finite, %d OK (%d failed) %d minor " + "arithmetic errors\n", finite, nonfinite, ok, failcount, minorarith); + printf(" Error with >=%d digit precision %.2f%%\n", DBL_DIG, max_abs); + printf(" Error with < %d digit precision %.2f%%\n", DBL_DIG, max); + + return 0; +} + +/* Observe that valid FP numbers have the forms listed in the PNG extensions + * specification: + * + * [+,-]{integer,integer.fraction,.fraction}[{e,E}[+,-]integer] + * + * Test each of these in turn, including invalid cases. + */ +typedef enum checkfp_state +{ + start, fraction, exponent, states +} checkfp_state; + +/* The characters (other than digits) that characterize the states: */ +static const char none[] = ""; +static const char hexdigits[16] = "0123456789ABCDEF"; + +static const struct +{ + const char *start; /* Characters valid at the start */ + const char *end; /* Valid characters that end the state */ + const char *tests; /* Characters to test after 2 digits seen */ +} +state_characters[states] = +{ + /* start: */ { "+-.", ".eE", "+-.e*0369" }, + /* fraction: */ { none, "eE", "+-.E#0147" }, + /* exponent: */ { "+-", none, "+-.eE^0258" } +}; + +typedef struct +{ + char number[1024]; /* Buffer for number being tested */ + int limit; /* Command line limit */ + int verbose; /* Shadows global variable */ + int ctimes; /* Number of numbers tested */ + int cmillions; /* Count of millions of numbers */ + int cinvalid; /* Invalid strings checked */ + int cnoaccept; /* Characters not accepted */ +} +checkfp_command; + +typedef struct +{ + int cnumber; /* Index into number string */ + checkfp_state check_state; /* Current number state */ + int at_start; /* At start (first character) of state */ + int cdigits_in_state; /* Digits seen in that state */ + int limit; /* Limit on same for checking all chars */ + int state; /* Current parser state */ + int is_negative; /* Number is negative */ + int is_zero; /* Number is (still) zero */ + int number_was_valid; /* Previous character validity */ +} +checkfp_control; + +static int check_all_characters(checkfp_command *co, checkfp_control c); + +static int check_some_characters(checkfp_command *co, checkfp_control c, + const char *tests); + +static int check_one_character(checkfp_command *co, checkfp_control c, int ch) +{ + /* Test this character (ch) to ensure the parser does the correct thing. + */ + png_size_t index = 0; + const char test = (char)ch; + const int number_is_valid = png_check_fp_number(&test, 1, &c.state, &index); + const int character_accepted = (index == 1); + + if (c.check_state != exponent && isdigit(ch) && ch != '0') + c.is_zero = 0; + + if (c.check_state == start && c.at_start && ch == '-') + c.is_negative = 1; + + if (isprint(ch)) + co->number[c.cnumber++] = (char)ch; + else + { + co->number[c.cnumber++] = '<'; + co->number[c.cnumber++] = hexdigits[(ch >> 4) & 0xf]; + co->number[c.cnumber++] = hexdigits[ch & 0xf]; + co->number[c.cnumber++] = '>'; + } + co->number[c.cnumber] = 0; + + if (co->verbose > 1) + fprintf(stderr, "%s\n", co->number); + + if (++(co->ctimes) == 1000000) + { + if (co->verbose == 1) + fputc('.', stderr); + co->ctimes = 0; + ++(co->cmillions); + } + + if (!number_is_valid) + ++(co->cinvalid); + + if (!character_accepted) + ++(co->cnoaccept); + + /* This should never fail (it's a serious bug if it does): */ + if (index != 0 && index != 1) + { + fprintf(stderr, "%s: read beyond end of string (%lu)\n", co->number, + (unsigned long)index); + return 0; + } + + /* Validate the new state, note that the PNG_FP_IS_ macros all return + * false unless the number is valid. + */ + if (PNG_FP_IS_NEGATIVE(c.state) != + (number_is_valid && !c.is_zero && c.is_negative)) + { + fprintf(stderr, "%s: negative when it is not\n", co->number); + return 0; + } + + if (PNG_FP_IS_ZERO(c.state) != (number_is_valid && c.is_zero)) + { + fprintf(stderr, "%s: zero when it is not\n", co->number); + return 0; + } + + if (PNG_FP_IS_POSITIVE(c.state) != + (number_is_valid && !c.is_zero && !c.is_negative)) + { + fprintf(stderr, "%s: positive when it is not\n", co->number); + return 0; + } + + /* Testing a digit */ + if (isdigit(ch)) + { + if (!character_accepted) + { + fprintf(stderr, "%s: digit '%c' not accepted\n", co->number, ch); + return 0; + } + + if (!number_is_valid) + { + fprintf(stderr, "%s: saw a digit (%c) but number not valid\n", + co->number, ch); + return 0; + } + + ++c.cdigits_in_state; + c.at_start = 0; + c.number_was_valid = 1; + + /* Continue testing characters in this state. Either test all of + * them or, if we have already seen one digit in this state, just test a + * limited set. + */ + if (c.cdigits_in_state < 1) + return check_all_characters(co, c); + + else + return check_some_characters(co, c, + state_characters[c.check_state].tests); + } + + /* A non-digit; is it allowed here? */ + else if (((ch == '+' || ch == '-') && c.check_state != fraction && + c.at_start) || + (ch == '.' && c.check_state == start) || + ((ch == 'e' || ch == 'E') && c.number_was_valid && + c.check_state != exponent)) + { + if (!character_accepted) + { + fprintf(stderr, "%s: character '%c' not accepted\n", co->number, ch); + return 0; + } + + /* The number remains valid after start of fraction but nowhere else. */ + if (number_is_valid && (c.check_state != start || ch != '.')) + { + fprintf(stderr, "%s: saw a non-digit (%c) but number valid\n", + co->number, ch); + return 0; + } + + c.number_was_valid = number_is_valid; + + /* Check for a state change. When changing to 'fraction' if the number + * is valid at this point set the at_start to false to allow an exponent + * 'e' to come next. + */ + if (c.check_state == start && ch == '.') + { + c.check_state = fraction; + c.at_start = !number_is_valid; + c.cdigits_in_state = 0; + c.limit = co->limit; + return check_all_characters(co, c); + } + + else if (c.check_state < exponent && (ch == 'e' || ch == 'E')) + { + c.check_state = exponent; + c.at_start = 1; + c.cdigits_in_state = 0; + c.limit = co->limit; + return check_all_characters(co, c); + } + + /* Else it was a sign, and the state doesn't change. */ + else + { + if (ch != '-' && ch != '+') + { + fprintf(stderr, "checkfp: internal error (1)\n"); + return 0; + } + + c.at_start = 0; + return check_all_characters(co, c); + } + } + + /* Testing an invalid character */ + else + { + if (character_accepted) + { + fprintf(stderr, "%s: character '%c' [0x%.2x] accepted\n", co->number, + ch, ch); + return 0; + } + + if (number_is_valid != c.number_was_valid) + { + fprintf(stderr, + "%s: character '%c' [0x%.2x] changed number validity\n", co->number, + ch, ch); + return 0; + } + + /* Do nothing - the parser has stuck; return success and keep going with + * the next character. + */ + } + + /* Successful return (the caller will try the next character.) */ + return 1; +} + +static int check_all_characters(checkfp_command *co, checkfp_control c) +{ + int ch; + + if (c.cnumber+4 < sizeof co->number) for (ch=0; ch<256; ++ch) + { + if (!check_one_character(co, c, ch)) + return 0; + } + + return 1; +} + +static int check_some_characters(checkfp_command *co, checkfp_control c, + const char *tests) +{ + int i; + + --(c.limit); + + if (c.cnumber+4 < sizeof co->number && c.limit >= 0) + { + if (c.limit > 0) for (i=0; tests[i]; ++i) + { + if (!check_one_character(co, c, tests[i])) + return 0; + } + + /* At the end check all the characters. */ + else + return check_all_characters(co, c); + } + + return 1; +} + +int validation_checkfp(int count, int argc, char **argv) +{ + int result; + checkfp_command command; + checkfp_control control; + + command.number[0] = 0; + command.limit = 3; + command.verbose = verbose; + command.ctimes = 0; + command.cmillions = 0; + command.cinvalid = 0; + command.cnoaccept = 0; + + while (--argc > 0) + { + ++argv; + if (argc > 1 && strcmp(*argv, "-l") == 0) + { + --argc; + command.limit = atoi(*++argv); + } + + else + { + fprintf(stderr, "unknown argument %s\n", *argv); + return 1; + } + } + + control.cnumber = 0; + control.check_state = start; + control.at_start = 1; + control.cdigits_in_state = 0; + control.limit = command.limit; + control.state = 0; + control.is_negative = 0; + control.is_zero = 1; + control.number_was_valid = 0; + + result = check_all_characters(&command, control); + + printf("checkfp: %s: checked %d,%.3d,%.3d,%.3d strings (%d invalid)\n", + result ? "pass" : "FAIL", command.cmillions / 1000, + command.cmillions % 1000, command.ctimes / 1000, command.ctimes % 1000, + command.cinvalid); + + return result; +} + +int validation_muldiv(int count, int argc, char **argv) +{ + int tested = 0; + int overflow = 0; + int error = 0; + int error64 = 0; + int passed = 0; + int randbits = 0; + png_uint_32 randbuffer; + png_fixed_point a; + png_int_32 times, div; + + while (--argc > 0) + { + fprintf(stderr, "unknown argument %s\n", *++argv); + return 1; + } + + /* Find out about the random number generator. */ + randbuffer = RAND_MAX; + while (randbuffer != 0) ++randbits, randbuffer >>= 1; + printf("Using random number generator that makes %d bits\n", randbits); + for (div=0; div<32; div += randbits) + randbuffer = (randbuffer << randbits) ^ rand(); + + a = 0; + times = div = 0; + do + { + png_fixed_point result; + /* NOTE: your mileage may vary, a type is required below that can + * hold 64 bits or more, if floating point is used a 64 bit or + * better mantissa is required. + */ + long long int fp, fpround; + unsigned long hi, lo; + int ok; + + /* Check the values, png_64bit_product can only handle positive + * numbers, so correct for that here. + */ + { + long u1, u2; + int n = 0; + if (a < 0) u1 = -a, n = 1; else u1 = a; + if (times < 0) u2 = -times, n = !n; else u2 = times; + png_64bit_product(u1, u2, &hi, &lo); + if (n) + { + /* -x = ~x+1 */ + lo = ((~lo) + 1) & 0xffffffff; + hi = ~hi; + if (lo == 0) ++hi; + } + } + + fp = a; + fp *= times; + if ((fp & 0xffffffff) != lo || ((fp >> 32) & 0xffffffff) != hi) + { + fprintf(stderr, "png_64bit_product %d * %d -> %lx|%.8lx not %llx\n", + a, times, hi, lo, fp); + ++error64; + } + + if (div != 0) + { + /* Round - this is C round to zero. */ + if ((fp < 0) != (div < 0)) + fp -= div/2; + else + fp += div/2; + + fp /= div; + fpround = fp; + /* Assume 2's complement here: */ + ok = fpround <= PNG_UINT_31_MAX && + fpround >= -1-(long long int)PNG_UINT_31_MAX; + if (!ok) ++overflow; + } + else + ok = 0, ++overflow, fpround = fp/*misleading*/; + + if (verbose) + fprintf(stderr, "TEST %d * %d / %d -> %lld (%s)\n", a, times, div, + fp, ok ? "ok" : "overflow"); + + ++tested; + if (png_muldiv(&result, a, times, div) != ok) + { + ++error; + if (ok) + fprintf(stderr, "%d * %d / %d -> overflow (expected %lld)\n", a, + times, div, fp); + else + fprintf(stderr, "%d * %d / %d -> %d (expected overflow %lld)\n", a, + times, div, result, fp); + } + else if (ok && result != fpround) + { + ++error; + fprintf(stderr, "%d * %d / %d -> %d not %lld\n", a, times, div, result, + fp); + } + else + ++passed; + + /* Generate three new values, this uses rand() and rand() only returns + * up to RAND_MAX. + */ + /* CRUDE */ + a += times; + times += div; + div = randbuffer; + randbuffer = (randbuffer << randbits) ^ rand(); + } + while (--count > 0); + + printf("%d tests including %d overflows, %d passed, %d failed (%d 64 bit " + "errors)\n", tested, overflow, passed, error, error64); + return 0; +} + +/* When FP is on this just becomes a speed test - compile without FP to get real + * validation. + */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED +#define LN2 .000010576586617430806112933839 /* log(2)/65536 */ +#define L2INV 94548.46219969910586572651 /* 65536/log(2) */ + +/* For speed testing, need the internal functions too: */ +static png_uint_32 png_log8bit(unsigned x) +{ + if (x > 0) + return (png_uint_32)floor(.5-log(x/255.)*L2INV); + + return 0xffffffff; +} + +static png_uint_32 png_log16bit(png_uint_32 x) +{ + if (x > 0) + return (png_uint_32)floor(.5-log(x/65535.)*L2INV); + + return 0xffffffff; +} + +static png_uint_32 png_exp(png_uint_32 x) +{ + return (png_uint_32)floor(.5 + exp(x * -LN2) * 0xffffffffU); +} + +static png_byte png_exp8bit(png_uint_32 log) +{ + return (png_byte)floor(.5 + exp(log * -LN2) * 255); +} + +static png_uint_16 png_exp16bit(png_uint_32 log) +{ + return (png_uint_16)floor(.5 + exp(log * -LN2) * 65535); +} +#endif /* FLOATING_ARITHMETIC */ + +int validation_gamma(int argc, char **argv) +{ + double gamma[9] = { 2.2, 1.8, 1.52, 1.45, 1., 1/1.45, 1/1.52, 1/1.8, 1/2.2 }; + double maxerr; + int i, silent=0, onlygamma=0; + + /* Silence the output with -s, just test the gamma functions with -g: */ + while (--argc > 0) + if (strcmp(*++argv, "-s") == 0) + silent = 1; + else if (strcmp(*argv, "-g") == 0) + onlygamma = 1; + else + { + fprintf(stderr, "unknown argument %s\n", *argv); + return 1; + } + + if (!onlygamma) + { + /* First validate the log functions: */ + maxerr = 0; + for (i=0; i<256; ++i) + { + double correct = -log(i/255.)/log(2.)*65536; + double error = png_log8bit(i) - correct; + + if (i != 0 && fabs(error) > maxerr) + maxerr = fabs(error); + + if (i == 0 && png_log8bit(i) != 0xffffffff || + i != 0 && png_log8bit(i) != floor(correct+.5)) + { + fprintf(stderr, "8 bit log error: %d: got %u, expected %f\n", + i, png_log8bit(i), correct); + } + } + + if (!silent) + printf("maximum 8 bit log error = %f\n", maxerr); + + maxerr = 0; + for (i=0; i<65536; ++i) + { + double correct = -log(i/65535.)/log(2.)*65536; + double error = png_log16bit(i) - correct; + + if (i != 0 && fabs(error) > maxerr) + maxerr = fabs(error); + + if (i == 0 && png_log16bit(i) != 0xffffffff || + i != 0 && png_log16bit(i) != floor(correct+.5)) + { + if (error > .68) /* By experiment error is less than .68 */ + { + fprintf(stderr, "16 bit log error: %d: got %u, expected %f" + " error: %f\n", i, png_log16bit(i), correct, error); + } + } + } + + if (!silent) + printf("maximum 16 bit log error = %f\n", maxerr); + + /* Now exponentiations. */ + maxerr = 0; + for (i=0; i<=0xfffff; ++i) + { + double correct = exp(-i/65536. * log(2.)) * (65536. * 65536); + double error = png_exp(i) - correct; + + if (fabs(error) > maxerr) + maxerr = fabs(error); + if (fabs(error) > 1883) /* By experiment. */ + { + fprintf(stderr, "32 bit exp error: %d: got %u, expected %f" + " error: %f\n", i, png_exp(i), correct, error); + } + } + + if (!silent) + printf("maximum 32 bit exp error = %f\n", maxerr); + + maxerr = 0; + for (i=0; i<=0xfffff; ++i) + { + double correct = exp(-i/65536. * log(2.)) * 255; + double error = png_exp8bit(i) - correct; + + if (fabs(error) > maxerr) + maxerr = fabs(error); + if (fabs(error) > .50002) /* By experiment */ + { + fprintf(stderr, "8 bit exp error: %d: got %u, expected %f" + " error: %f\n", i, png_exp8bit(i), correct, error); + } + } + + if (!silent) + printf("maximum 8 bit exp error = %f\n", maxerr); + + maxerr = 0; + for (i=0; i<=0xfffff; ++i) + { + double correct = exp(-i/65536. * log(2.)) * 65535; + double error = png_exp16bit(i) - correct; + + if (fabs(error) > maxerr) + maxerr = fabs(error); + if (fabs(error) > .524) /* By experiment */ + { + fprintf(stderr, "16 bit exp error: %d: got %u, expected %f" + " error: %f\n", i, png_exp16bit(i), correct, error); + } + } + + if (!silent) + printf("maximum 16 bit exp error = %f\n", maxerr); + } /* !onlygamma */ + + /* Test the overall gamma correction. */ + for (i=0; i<9; ++i) + { + unsigned j; + double g = gamma[i]; + png_fixed_point gfp = floor(g * PNG_FP_1 + .5); + + if (!silent) + printf("Test gamma %f\n", g); + + maxerr = 0; + for (j=0; j<256; ++j) + { + double correct = pow(j/255., g) * 255; + png_byte out = png_gamma_8bit_correct(j, gfp); + double error = out - correct; + + if (fabs(error) > maxerr) + maxerr = fabs(error); + if (out != floor(correct+.5)) + { + fprintf(stderr, "8bit %d ^ %f: got %d expected %f error %f\n", + j, g, out, correct, error); + } + } + + if (!silent) + printf("gamma %f: maximum 8 bit error %f\n", g, maxerr); + + maxerr = 0; + for (j=0; j<65536; ++j) + { + double correct = pow(j/65535., g) * 65535; + png_uint_16 out = png_gamma_16bit_correct(j, gfp); + double error = out - correct; + + if (fabs(error) > maxerr) + maxerr = fabs(error); + if (fabs(error) > 1.62) + { + fprintf(stderr, "16bit %d ^ %f: got %d expected %f error %f\n", + j, g, out, correct, error); + } + } + + if (!silent) + printf("gamma %f: maximum 16 bit error %f\n", g, maxerr); + } + + return 0; +} + +/**************************** VALIDATION TESTS ********************************/ +/* Various validation routines are included herein, they require some + * definition for png_warning and png_error, seetings of VALIDATION: + * + * 1: validates the ASCII to floating point conversions + * 2: validates png_muldiv + * 3: accuracy test of fixed point gamma tables + */ + +/* The following COUNT (10^8) takes about 1 hour on a 1GHz Pentium IV + * processor. + */ +#define COUNT 1000000000 + +int main(int argc, char **argv) +{ + int count = COUNT; + + while (argc > 1) + { + if (argc > 2 && strcmp(argv[1], "-c") == 0) + { + count = atoi(argv[2]); + argc -= 2; + argv += 2; + } + + else if (strcmp(argv[1], "-v") == 0) + { + ++verbose; + --argc; + ++argv; + } + + else + break; + } + + if (count > 0 && argc > 1) + { + if (strcmp(argv[1], "ascii") == 0) + return validation_ascii_to_fp(count, argc-1, argv+1); + else if (strcmp(argv[1], "checkfp") == 0) + return validation_checkfp(count, argc-1, argv+1); + else if (strcmp(argv[1], "muldiv") == 0) + return validation_muldiv(count, argc-1, argv+1); + else if (strcmp(argv[1], "gamma") == 0) + return validation_gamma(argc-1, argv+1); + } + + /* Bad argument: */ + fprintf(stderr, + "usage: tarith [-v] [-c count] {ascii,muldiv,gamma} [args]\n"); + fprintf(stderr, " arguments: ascii [-a (all results)] [-e error%%]\n"); + fprintf(stderr, " checkfp [-l max-number-chars]\n"); + fprintf(stderr, " muldiv\n"); + fprintf(stderr, " gamma -s (silent) -g (only gamma; no log)\n"); + return 1; +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/timepng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/timepng.c new file mode 100644 index 00000000000..523627f3843 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/libtests/timepng.c @@ -0,0 +1,303 @@ +/* timepng.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Load an arbitrary number of PNG files (from the command line, or, if there + * are no arguments on the command line, from stdin) then run a time test by + * reading each file by row. The test does nothing with the read result and + * does no transforms. The only output is a time as a floating point number of + * seconds with 9 decimal digits. + */ +#define _POSIX_C_SOURCE 199309L /* for clock_gettime */ + +#include +#include +#include + +#include + +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include +#endif + +/* Define the following to use this test against your installed libpng, rather + * than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include +#else +# include "../../png.h" +#endif + +static int read_png(FILE *fp) +{ + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); + png_infop info_ptr = NULL; + png_bytep row = NULL, display = NULL; + + if (png_ptr == NULL) + return 0; + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (row != NULL) free(row); + if (display != NULL) free(display); + return 0; + } + + png_init_io(png_ptr, fp); + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + png_read_info(png_ptr, info_ptr); + + { + png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + row = malloc(rowbytes); + display = malloc(rowbytes); + + if (row == NULL || display == NULL) + png_error(png_ptr, "OOM allocating row buffers"); + + { + png_uint_32 height = png_get_image_height(png_ptr, info_ptr); + int passes = png_set_interlace_handling(png_ptr); + int pass; + + png_start_read_image(png_ptr); + + for (pass = 0; pass < passes; ++pass) + { + png_uint_32 y = height; + + /* NOTE: this trashes the row each time; interlace handling won't + * work, but this avoids memory thrashing for speed testing. + */ + while (y-- > 0) + png_read_row(png_ptr, row, display); + } + } + } + + /* Make sure to read to the end of the file: */ + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + free(row); + free(display); + return 1; +} + +static int mytime(struct timespec *t) +{ + /* Do the timing using clock_gettime and the per-process timer. */ + if (!clock_gettime(CLOCK_PROCESS_CPUTIME_ID, t)) + return 1; + + perror("CLOCK_PROCESS_CPUTIME_ID"); + fprintf(stderr, "timepng: could not get the time\n"); + return 0; +} + +static int perform_one_test(FILE *fp, int nfiles) +{ + int i; + struct timespec before, after; + + /* Clear out all errors: */ + rewind(fp); + + if (mytime(&before)) + { + for (i=0; i 1) + { + int i; + + for (i=1; i 0) + ok = perform_one_test(fp, nfiles); + + else + fprintf(stderr, "usage: timepng {files} or ls files | timepng\n"); + } + + (void)fclose(fp); + } + + else + fprintf(stderr, "timepng: could not open temporary file\n"); + + /* Exit code 0 on success. */ + return ok == 0; +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/README b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/README new file mode 100644 index 00000000000..e17fe35b6a8 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/README @@ -0,0 +1,5 @@ + +This demonstrates the use of PNG_USER_CONFIG, pngusr.h and pngusr.dfa +to build minimal decoder, encoder, and progressive reader applications. + +See the individual README and pngusr.dfa files for more explanation. diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/README b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/README new file mode 100644 index 00000000000..fa979fcb727 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/README @@ -0,0 +1,10 @@ +This demonstrates the use of PNG_USER_CONFIG, pngusr.h and pngusr.dfa + +The makefile builds a minimal read-only decoder with embedded libpng +and zlib. + +Specify the location of the zlib source (1.2.1 or later) as ZLIBSRC +on the make command line. + +If you prefer to use the shared libraries, go to contrib/pngminus +and build the png2pnm application there. diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/makefile b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/makefile new file mode 100644 index 00000000000..dafba64b74a --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/makefile @@ -0,0 +1,150 @@ +# Makefile for PngMinus (pngm2pnm) +# Linux / Unix + +#CC=cc +CC=gcc +LD=$(CC) + +# If awk fails try +# make AWK=nawk + +# If cpp fails try +# make CPP=/lib/cpp + +RM=rm -f +COPY=cp + +CFLAGS=-DPNG_USER_CONFIG -DNO_GZCOMPRESS -DZ_SOLO -DNO_GZIP -I. -O1 + +C=.c +O=.o +L=.a +E= + +# Where to find the source code: +PNGSRC =../../.. +ZLIBSRC=$(PNGSRC)/../zlib +PROGSRC=$(PNGSRC)/contrib/pngminus + +# Zlib (minimal inflate requirements - crc32 is used by libpng) +# zutil can be eliminated if you provide your own zcalloc and zcfree +ZSRCS = adler32$(C) crc32$(C) \ + inffast$(C) inflate$(C) inftrees$(C) \ + zutil$(C) + +# Standard headers +ZH = zlib.h crc32.h inffast.h inffixed.h \ + inflate.h inftrees.h zutil.h + +# Machine generated headers +ZCONF = zconf.h + +# Headers callers use +ZINC = zlib.h $(ZCONF) + +# Headers the Zlib source uses +ZHDRS = $(ZH) $(ZCONF) + +ZOBJS = adler32$(O) crc32$(O) \ + inffast$(O) inflate$(O) inftrees$(O) \ + zutil$(O) + +# libpng +PNGSRCS=png$(C) pngerror$(C) pngget$(C) pngmem$(C) \ + pngread$(C) pngrio$(C) pngrtran$(C) pngrutil$(C) \ + pngset$(C) pngtrans$(C) + +# Standard headers +PNGH =png.h pngconf.h pngdebug.h pnginfo.h pngpriv.h pngstruct.h + +# Machine generated headers +PNGCONF=pnglibconf.h + +# Headers callers use +PNGINC= png.h pngconf.h pngusr.h $(PNGCONF) + +# Headers the PNG library uses +PNGHDRS=$(PNGH) $(PNGCONF) pngusr.h + +PNGOBJS=png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ + pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ + pngset$(O) pngtrans$(O) + +PROGSRCS= pngm2pnm$(C) +PROGHDRS= +PROGDOCS= +PROGOBJS= pngm2pnm$(O) + +OBJS = $(PROGOBJS) $(PNGOBJS) $(ZOBJS) + +# implicit make rules ------------------------------------------------------- + +# note: dependencies do not work on implicit rule lines +.c$(O): + $(CC) -c $(CFLAGS) $< + +# dependencies + +all: pngm2pnm$(E) + +pngm2pnm$(E): $(OBJS) + $(LD) -o pngm2pnm$(E) $(OBJS) + +# The DFA_XTRA setting turns all libpng options off then +# turns on those required for this minimal build. +# The CPP_FLAGS setting causes pngusr.h to be included in +# both the build of pnglibconf.h and, subsequently, when +# building libpng itself. +$(PNGCONF): $(PNGSRC)/scripts/pnglibconf.mak\ + $(PNGSRC)/scripts/pnglibconf.dfa \ + $(PNGSRC)/scripts/options.awk pngusr.h pngusr.dfa + $(RM) pnglibconf.h pnglibconf.dfn + $(MAKE) $(MAKEFLAGS) -f $(PNGSRC)/scripts/pnglibconf.mak\ + srcdir=$(PNGSRC) CPPFLAGS="-DPNG_USER_CONFIG"\ + DFA_XTRA="pngusr.dfa" $@ + +clean: + $(MAKE) $(MAKEFLAGS) -f $(PNGSRC)/scripts/pnglibconf.mak\ + srcdir=$(PNGSRC) clean + $(RM) pngm2pnm$(O) + $(RM) pngm2pnm$(E) + $(RM) $(OBJS) + +# distclean also removes the copied source and headers +distclean: clean + $(RM) -r scripts # historical reasons + $(RM) $(PNGSRCS) $(PNGH) + $(RM) $(ZSRCS) $(ZH) $(ZCONF) + $(RM) $(PROGSRCS) $(PROGHDRS) $(PROGDOCS) + +# Header file dependencies: +$(PROGOBJS): $(PROGHDRS) $(PNGINC) $(ZINC) +$(PNGOBJS): $(PNGHDRS) $(ZINC) +$(ZOBJS): $(ZHDRS) + +# Gather the source code from the respective directories +$(PNGSRCS) $(PNGH): $(PNGSRC)/$@ + $(RM) $@ + $(COPY) $(PNGSRC)/$@ $@ + +# No dependency on the ZLIBSRC target so that it only needs +# to be specified once. +$(ZSRCS) $(ZH): + $(RM) $@ + $(COPY) $(ZLIBSRC)/$@ $@ + +# The unconfigured zconf.h varies in name according to the +# zlib release +$(ZCONF): + $(RM) $@ + @for f in zconf.h.in zconf.in.h zconf.h; do\ + test -r $(ZLIBSRC)/$$f &&\ + echo $(COPY) $(ZLIBSRC)/$$f $@ &&\ + $(COPY) $(ZLIBSRC)/$$f $@ && exit 0;\ + done; echo copy: $(ZLIBSRC)/zconf.h not found; exit 1 + +pngm2pnm.c: $(PROGSRC)/png2pnm.c + $(RM) $@ + $(COPY) $(PROGSRC)/png2pnm.c $@ + +# End of makefile for pngm2pnm diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.dfa b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.dfa new file mode 100644 index 00000000000..4f402721ab0 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.dfa @@ -0,0 +1,40 @@ +# pngminim/decoder/pngusr.dfa +# +# Copyright (c) 2010-2013 Glenn Randers-Pehrson +# +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h + +# First all the build options off: + +everything = off + +# All that is required is some read code. This example switches +# on the sequential read code (see ../preader for a progressive +# read example). + +option SEQUENTIAL_READ on + +# You must choose fixed or floating point arithmetic: +# option FLOATING_POINT on + +option FIXED_POINT on + +# You must chose the internal fixed point implementation or to +# use the system floating point. The latter is considerably +# smaller (by about 1kbyte on an x86 system): +# option FLOATING_ARITHMETIC on + +option FLOATING_ARITHMETIC off + +# Your program will probably need other options. The example +# program here, pngm2pnm, requires the following. Take a look +# at pnglibconf.h to find out the full set of what has to be +# enabled to make the following work. + +option SETJMP on +option STDIO on +option READ_EXPAND on +option READ_STRIP_16_TO_8 on +option USER_LIMITS on diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.h new file mode 100644 index 00000000000..841da0c28a1 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/decoder/pngusr.h @@ -0,0 +1,24 @@ +/* minrdpngconf.h: headers to make a minimal png-read-only library + * + * Copyright (c) 2007, 2010-2013 Glenn Randers-Pehrson + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Derived from pngcrush.h, Copyright 1998-2007, Glenn Randers-Pehrson + */ + +#ifndef MINRDPNGCONF_H +#define MINRDPNGCONF_H + +/* To include pngusr.h set -DPNG_USER_CONFIG in CPPFLAGS */ + +/* List options to turn off features of the build that do not + * affect the API (so are not recorded in pnglibconf.h) + */ + +#define PNG_NO_WARNINGS +#define PNG_ALIGN_TYPE PNG_ALIGN_NONE + +#endif /* MINRDPNGCONF_H */ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/README b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/README new file mode 100644 index 00000000000..d8d9a6466e2 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/README @@ -0,0 +1,10 @@ +This demonstrates the use of PNG_USER_CONFIG and pngusr.h + +The makefile builds a minimal write-only encoder with embedded libpng +and zlib. + +Specify the location of the zlib source (1.2.1 or later) as ZLIBSRC +on the make command line. + +If you prefer to use the shared libraries, go to contrib/pngminus +and build the pnm2png application there. diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/makefile b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/makefile new file mode 100644 index 00000000000..810b8c8faa8 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/makefile @@ -0,0 +1,149 @@ +# Makefile for PngMinus (pnm2pngm) +# Linux / Unix + +#CC=cc +CC=gcc +LD=$(CC) + +# If awk fails try +# make AWK=nawk + +# If cpp fails try +# make CPP=/lib/cpp + +RM=rm -f +COPY=cp + +CFLAGS=-DPNG_USER_CONFIG -DZ_SOLO -DNO_GZIP -I. -O1 + +C=.c +O=.o +L=.a +E= + +# Where to find the source code: +PNGSRC =../../.. +ZLIBSRC=$(PNGSRC)/../zlib +PROGSRC=$(PNGSRC)/contrib/pngminus + +# Zlib +ZSRCS = adler32$(C) compress$(C) crc32$(C) deflate$(C) \ + trees$(C) zutil$(C) + +# Standard headers +#ZH = zlib.h crc32.h deflate.h trees.h zutil.h +ZH = zlib.h crc32.h deflate.h trees.h zutil.h + +# Machine generated headers +ZCONF = zconf.h + +# Headers callers use +ZINC = zlib.h $(ZCONF) + +# Headers the Zlib source uses +ZHDRS = $(ZH) $(ZCONF) + +# compress is not required; it is needed to link the zlib +# code because deflate defines an unused API function deflateBound +# which itself calls compressBound from compress. +ZOBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) \ + trees$(O) zutil$(O) + +# libpng +PNGSRCS=png$(C) pngerror$(C) pngget$(C) pngmem$(C) \ + pngset$(C) pngtrans$(C) pngwio$(C) pngwrite$(C) \ + pngwtran$(C) pngwutil$(C) + +# Standard headers +PNGH =png.h pngconf.h pngdebug.h pnginfo.h pngpriv.h pngstruct.h + +# Machine generated headers +PNGCONF=pnglibconf.h + +# Headers callers use +PNGINC= png.h pngconf.h pngusr.h $(PNGCONF) + +# Headers the PNG library uses +PNGHDRS=$(PNGH) $(PNGCONF) pngusr.h + +PNGOBJS=png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ + pngset$(O) pngtrans$(O) pngwio$(O) pngwrite$(O) \ + pngwtran$(O) pngwutil$(O) + +PROGSRCS= pnm2pngm$(C) +PROGHDRS= +PROGDOCS= +PROGOBJS= pnm2pngm$(O) + +OBJS = $(PROGOBJS) $(PNGOBJS) $(ZOBJS) + +# implicit make rules ------------------------------------------------------- + +.c$(O): + $(CC) -c $(CFLAGS) $< + +# dependencies + +all: pnm2pngm$(E) + +pnm2pngm$(E): $(OBJS) + $(LD) -o pnm2pngm$(E) $(OBJS) + +# The DFA_XTRA setting turns all libpng options off then +# turns on those required for this minimal build. +# The CPP_FLAGS setting causes pngusr.h to be included in +# both the build of pnglibconf.h and, subsequently, when +# building libpng itself. +$(PNGCONF): $(PNGSRC)/scripts/pnglibconf.mak\ + $(PNGSRC)/scripts/pnglibconf.dfa \ + $(PNGSRC)/scripts/options.awk pngusr.h pngusr.dfa + $(RM) pnglibconf.h pnglibconf.dfn + $(MAKE) $(MAKEFLAGS) -f $(PNGSRC)/scripts/pnglibconf.mak\ + srcdir=$(PNGSRC) CPPFLAGS="-DPNG_USER_CONFIG"\ + DFA_XTRA="pngusr.dfa" $@ + +clean: + $(MAKE) $(MAKEFLAGS) -f $(PNGSRC)/scripts/pnglibconf.mak\ + srcdir=$(PNGSRC) clean + $(RM) pnm2pngm$(O) + $(RM) pnm2pngm$(E) + $(RM) $(OBJS) + +# distclean also removes the copied source and headers +distclean: clean + $(RM) -r scripts # historical reasons + $(RM) $(PNGSRCS) $(PNGH) + $(RM) $(ZSRCS) $(ZH) $(ZCONF) + $(RM) $(PROGSRCS) $(PROGHDRS) $(PROGDOCS) + +# Header file dependencies: +$(PROGOBJS): $(PROGHDRS) $(PNGINC) $(ZINC) +$(PNGOBJS): $(PNGHDRS) $(ZINC) +$(ZOBJS): $(ZHDRS) + +# Gather the source code from the respective directories +$(PNGSRCS) $(PNGH): $(PNGSRC)/$@ + $(RM) $@ + $(COPY) $(PNGSRC)/$@ $@ + +# No dependency on the ZLIBSRC target so that it only needs +# to be specified once. +$(ZSRCS) $(ZH): + $(RM) $@ + $(COPY) $(ZLIBSRC)/$@ $@ + +# The unconfigured zconf.h varies in name according to the +# zlib release +$(ZCONF): + $(RM) $@ + @for f in zconf.h.in zconf.in.h zconf.h; do\ + test -r $(ZLIBSRC)/$$f &&\ + echo $(COPY) $(ZLIBSRC)/$$f $@ &&\ + $(COPY) $(ZLIBSRC)/$$f $@ && exit 0;\ + done; echo copy: $(ZLIBSRC)/zconf.h not found; exit 1 + +pnm2pngm.c: $(PROGSRC)/pnm2png.c + $(RM) $@ + $(COPY) $(PROGSRC)/pnm2png.c $@ + +# End of makefile for pnm2pngm diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.dfa b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.dfa new file mode 100644 index 00000000000..88d8b2a07ab --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.dfa @@ -0,0 +1,35 @@ +# pngminim/encoder/pngusr.dfa +# +# Copyright (c) 2010-2013 Glenn Randers-Pehrson +# +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h + +# First all the build options off: + +everything = off + +# Switch on the write code - this makes a minimalist encoder + +option WRITE on + +# You must choose fixed or floating point arithmetic: +# option FLOATING_POINT on + +option FIXED_POINT on + +# You must chose the internal fixed point implementation or to +# use the system floating point. The latter is considerably +# smaller (by about 1kbyte on an x86 system): +# option FLOATING_ARITHMETIC on + +option FLOATING_ARITHMETIC off + +# Your program will probably need other options. The example +# program here, pnm2pngm, requires the following. Take a look +# at pnglibconf.h to find out the full set of what has to be +# enabled to make the following work. + +option SETJMP on +option STDIO on diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.h new file mode 100644 index 00000000000..a050ef3eb63 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/encoder/pngusr.h @@ -0,0 +1,24 @@ +/* minwrpngconf.h: headers to make a minimal png-write-only library + * + * Copyright (c) 2007, 2010-2013 Glenn Randers-Pehrson + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Derived from pngcrush.h, Copyright 1998-2007, Glenn Randers-Pehrson + */ + +#ifndef MINWRPNGCONF_H +#define MINWRPNGCONF_H + +/* To include pngusr.h set -DPNG_USER_CONFIG in CPPFLAGS */ + +/* List options to turn off features of the build that do not + * affect the API (so are not recorded in pnglibconf.h) + */ + +#define PNG_NO_WARNINGS +#define PNG_ALIGN_TYPE PNG_ALIGN_NONE + +#endif /* MINWRPNGCONF_H */ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/README b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/README new file mode 100644 index 00000000000..faa83560a72 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/README @@ -0,0 +1,15 @@ +This demonstrates the use of PNG_USER_CONFIG and pngusr.h + +The makefile builds a minimal read-only progressive decoder with +embedded libpng, zlib and your system's X library. + +Specify the location of the zlib source (1.2.1 or later) as ZLIBSRC +on the make command line. + +Edit makefile if required, to find your X library and include files, +then + + make ZLIBSRC=directory + +If you prefer to use the shared libraries, go to contrib/gregbook +and build the rpng2-x application there. diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/makefile b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/makefile new file mode 100644 index 00000000000..ecc05c7bf69 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/makefile @@ -0,0 +1,165 @@ +# Makefile for PngMinus (rpng2) +# Linux / Unix + +#CC=cc +CC=gcc +LD=$(CC) + +# If awk fails try +# make AWK=nawk + +# If cpp fails try +# make CPP=/lib/cpp + +RM=rm -f +COPY=cp + +#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 + +#XINC = -I/usr/local/include # FreeBSD +#XLIB = -L/usr/local/lib -lX11 + +#LIBS = $(XLIB) +LIBS = $(XLIB) -lm #platforms that need libm + +CFLAGS=-DPNG_USER_CONFIG -DNO_GZCOMPRESS -DZ_SOLO -DNO_GZIP -I. $(XINC) -O1 + +C=.c +O=.o +L=.a +E= + +# Where to find the source code: +PNGSRC =../../.. +ZLIBSRC=$(PNGSRC)/../zlib +PROGSRC=$(PNGSRC)/contrib/gregbook + +# Zlib (minimal inflate requirements - crc32 is used by libpng) +# zutil can be eliminated if you provide your own zcalloc and zcfree +ZSRCS = adler32$(C) crc32$(C) \ + inffast$(C) inflate$(C) inftrees$(C) \ + zutil$(C) + +# Standard headers +ZH = zlib.h crc32.h inffast.h inffixed.h \ + inflate.h inftrees.h zutil.h + +# Machine generated headers +ZCONF = zconf.h + +# Headers callers use +ZINC = zlib.h $(ZCONF) + +# Headers the Zlib source uses +ZHDRS = $(ZH) $(ZCONF) + +ZOBJS = adler32$(O) crc32$(O) \ + inffast$(O) inflate$(O) inftrees$(O) \ + zutil$(O) + +# libpng +PNGSRCS=png$(C) pngerror$(C) pngget$(C) pngmem$(C) \ + pngpread$(C) pngread$(C) pngrio$(C) pngrtran$(C) pngrutil$(C) \ + pngset$(C) pngtrans$(C) + +# Standard headers +PNGH =png.h pngconf.h pngdebug.h pnginfo.h pngpriv.h pngstruct.h + +# Machine generated headers +PNGCONF=pnglibconf.h + +# Headers callers use +PNGINC= png.h pngconf.h pngusr.h $(PNGCONF) + +# Headers the PNG library uses +PNGHDRS=$(PNGH) $(PNGCONF) pngusr.h + +PNGOBJS=png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ + pngpread$(O) pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ + pngset$(O) pngtrans$(O) + +PROGSRCS= rpng2-x$(C) readpng2$(C) +PROGHDRS= readpng2.h +PROGDOCS= COPYING LICENSE +PROGOBJS= rpng2-x$(O) readpng2$(O) + +OBJS = $(PROGOBJS) $(PNGOBJS) $(ZOBJS) + +# implicit make rules ------------------------------------------------------- + +.c$(O): + $(CC) -c $(CFLAGS) $< + +# dependencies + +all: $(PROGDOCS) rpng2-x$(E) + +rpng2-x$(E): $(OBJS) + $(LD) -o rpng2-x$(E) $(OBJS) $(LIBS) + +# The DFA_XTRA setting turns all libpng options off then +# turns on those required for this minimal build. +# The CPP_FLAGS setting causes pngusr.h to be included in +# both the build of pnglibconf.h and, subsequently, when +# building libpng itself. +$(PNGCONF): $(PNGSRC)/scripts/pnglibconf.mak\ + $(PNGSRC)/scripts/pnglibconf.dfa \ + $(PNGSRC)/scripts/options.awk pngusr.h pngusr.dfa + $(RM) pnglibconf.h pnglibconf.dfn + $(MAKE) $(MAKEFLAGS) -f $(PNGSRC)/scripts/pnglibconf.mak\ + srcdir=$(PNGSRC) CPPFLAGS="-DPNG_USER_CONFIG"\ + DFA_XTRA="pngusr.dfa" $@ + +clean: + $(MAKE) $(MAKEFLAGS) -f $(PNGSRC)/scripts/pnglibconf.mak\ + srcdir=$(PNGSRC) clean + $(RM) rpng2-x$(O) + $(RM) rpng2-x$(E) + $(RM) $(OBJS) + +# distclean also removes the copied source and headers +distclean: clean + $(RM) -r scripts # historical reasons + $(RM) $(PNGSRCS) $(PNGH) + $(RM) $(ZSRCS) $(ZH) $(ZCONF) + $(RM) $(PROGSRCS) $(PROGHDRS) $(PROGDOCS) + +# Header file dependencies: +$(PROGOBJS): $(PROGHDRS) $(PNGINC) $(ZINC) +$(PNGOBJS): $(PNGHDRS) $(ZINC) +$(ZOBJS): $(ZHDRS) + +# Gather the source code from the respective directories +$(PNGSRCS) $(PNGH): $(PNGSRC)/$@ + $(RM) $@ + $(COPY) $(PNGSRC)/$@ $@ + +# No dependency on the ZLIBSRC target so that it only needs +# to be specified once. +$(ZSRCS) $(ZH): + $(RM) $@ + $(COPY) $(ZLIBSRC)/$@ $@ + +# The unconfigured zconf.h varies in name according to the +# zlib release +$(ZCONF): + $(RM) $@ + @for f in zconf.h.in zconf.in.h zconf.h; do\ + test -r $(ZLIBSRC)/$$f &&\ + echo $(COPY) $(ZLIBSRC)/$$f $@ &&\ + $(COPY) $(ZLIBSRC)/$$f $@ && exit 0;\ + done; echo copy: $(ZLIBSRC)/zconf.h not found; exit 1 + +$(PROGSRCS) $(PROGHDRS) $(PROGDOCS): $(PROGSRC)/$@ + $(RM) $@ + $(COPY) $(PROGSRC)/$@ $@ + +# End of makefile for rpng2-x diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.dfa b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.dfa new file mode 100644 index 00000000000..ac297f41bd7 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.dfa @@ -0,0 +1,40 @@ +# pngminim/preader/pngusr.dfa +# +# Copyright (c) 2010-2013 Glenn Randers-Pehrson +# +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h + +# First all the build options off: + +everything = off + +# Just switch on the progressive read code + +option PROGRESSIVE_READ on + +# You may choose fixed or floating point APIs: +# option FLOATING_POINT on + +option FIXED_POINT on + +# You must chose the internal fixed point implementation or to +# use the system floating point. The latter is considerably +# smaller (by about 1kbyte on an x86 system): + +option FLOATING_ARITHMETIC on +# option FLOATING_ARITHMETIC off + +# Your program will probably need other options. The example +# program here, rpng2-x, requires the following. Take a look +# at pnglibconf.h to find out the full set of what has to be +# enabled to make the following work. + +option SETJMP on +option STDIO on +option READ_bKGD on +option READ_GAMMA on +option READ_EXPAND on +option READ_STRIP_16_TO_8 on +option READ_GRAY_TO_RGB on diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.h new file mode 100644 index 00000000000..d84863472f6 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminim/preader/pngusr.h @@ -0,0 +1,24 @@ +/* minrdpngconf.h: headers to make a minimal png-read-only library + * + * Copyright (c) 2009, 2010-2013 Glenn Randers-Pehrson + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Derived from pngcrush.h, Copyright 1998-2007, Glenn Randers-Pehrson + */ + +#ifndef MINPRDPNGCONF_H +#define MINPRDPNGCONF_H + +/* To include pngusr.h set -DPNG_USER_CONFIG in CPPFLAGS */ + +/* List options to turn off features of the build that do not + * affect the API (so are not recorded in pnglibconf.h) + */ + +#define PNG_NO_WARNINGS +#define PNG_ALIGN_TYPE PNG_ALIGN_NONE + +#endif /* MINPRDPNGCONF_H */ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/README b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/README new file mode 100644 index 00000000000..bbe7407ecce --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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 . 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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makefile.std b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makefile.std new file mode 100644 index 00000000000..30317b77d43 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/libpng16 +#PNGLIB = -L$(PNGPATH)/lib -lpng16 +#PNGLIBS = $(PNGPATH)/lib/libpng16.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=$(PNGINC) $(ZINC) +LDLIBS=$(PNGLIB) $(ZLIB) +LDLIBSS=$(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) $(LDFLAGS) -o png2pnm$(E) png2pnm$(O) $(LDLIBS) -lm + +png2pnm-static$(E): png2pnm$(O) + $(LD) $(LDFLAGS) -o png2pnm-static$(E) png2pnm$(O) $(LDLIBSS) -lm + +pnm2png$(O): pnm2png$(C) + $(CC) -c $(CFLAGS) pnm2png$(C) + +pnm2png$(E): pnm2png$(O) + $(LD) $(LDFLAGS) -o pnm2png$(E) pnm2png$(O) $(LDLIBS) -lm + +pnm2png-static$(E): pnm2png$(O) + $(LD) $(LDFLAGS) -o pnm2png-static$(E) pnm2png$(O) $(LDLIBSS) -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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makefile.tc3 b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makefile.tc3 new file mode 100644 index 00000000000..404f18d5b15 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makevms.com b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/makevms.com new file mode 100644 index 00000000000..00561bcd0d7 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.bat b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.bat new file mode 100644 index 00000000000..449cf36750b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.c new file mode 100644 index 00000000000..aa9513ddc27 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.c @@ -0,0 +1,431 @@ +/* + * png2pnm.c --- conversion from PNG-file to PGM/PPM-file + * copyright (C) 1999 by Willem van Schaik + * + * 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 +#include +#ifdef __TURBOC__ +#include +#include +#endif +#include + +#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 conversion 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] .png [.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] .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_sig_cmp (buf, 0, 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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.sh b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/png2pnm.sh new file mode 100644 index 00000000000..b1c05370dff --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.bat b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.bat new file mode 100644 index 00000000000..911bb8dff9e --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.bat @@ -0,0 +1,4 @@ +make -f makefile.tc3 +call png2pnm.bat +call pnm2png.bat + diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.sh b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.sh new file mode 100644 index 00000000000..2a0a9d8fbba --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pngminus.sh @@ -0,0 +1,5 @@ +#!/bin/sh +make -f makefile.std +sh png2pnm.sh +sh pnm2png.sh + diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.bat b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.bat new file mode 100644 index 00000000000..f756cb84de4 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.c new file mode 100644 index 00000000000..d098e33cb7f --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.c @@ -0,0 +1,549 @@ +/* + * pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file + * copyright (C) 1999 by Willem van Schaik + * + * 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 +#include +#ifdef __TURBOC__ +#include +#include +#endif +#include + +#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] . [.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] .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; + unsigned long ul_width, ul_alpha_width; + unsigned long ul_height, ul_alpha_height; + unsigned long ul_maxval; + 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", &ul_width); + width = (png_uint_32) ul_width; + get_token(pnm_file, height_token); + sscanf (height_token, "%lu", &ul_height); + height = (png_uint_32) ul_height; + get_token(pnm_file, maxval_token); + sscanf (maxval_token, "%lu", &ul_maxval); + maxval = (png_uint_32) ul_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", &ul_width); + width = (png_uint_32) ul_width; + get_token(pnm_file, height_token); + sscanf (height_token, "%lu", &ul_height); + height = (png_uint_32) ul_height; + get_token(pnm_file, maxval_token); + sscanf (maxval_token, "%lu", &ul_maxval); + maxval = (png_uint_32) ul_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", &ul_alpha_width); + alpha_width=(png_uint_32) ul_alpha_width; + if (alpha_width != width) + return FALSE; + get_token(alpha_file, height_token); + sscanf (height_token, "%lu", &ul_alpha_height); + alpha_height = (png_uint_32) ul_alpha_height; + if (alpha_height != height) + return FALSE; + get_token(alpha_file, maxval_token); + sscanf (maxval_token, "%lu", &ul_maxval); + maxval = (png_uint_32) ul_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]; + unsigned long ul_ret_value; + 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", &ul_ret_value); + ret_value = (png_uint_32) ul_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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.sh b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngminus/pnm2png.sh new file mode 100644 index 00000000000..d79df2fae08 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/README b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/README new file mode 100644 index 00000000000..ec4af9473f1 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/README @@ -0,0 +1,105 @@ + +pngsuite +-------- +(c) Willem van Schaik, 1999, 2011, 2012 +Two images are by Glenn Randers-Pehrson, 2012 + +Permission to use, copy, modify, and distribute these images for any +purpose and without fee is hereby granted. + +The 15 "bas*.png" 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 "ft*.png" images are "free/libre" replacements for the transparent +corresponding t*.png images in the PngSuite. + +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 + + ftbbn0g01.png 1-bit grayscale, black bKGD + ftbbn0g02.png 2-bit grayscale, black bKGD + ftbbn0g04.png 4-bit grayscale, black bKGD + ftbbn2c16.png 16-bit truecolor, black bKGD + ftbbn3p08.png 8-bit paletted, black bKGD + ftbgn2c16.png 16-bit truecolor, gray bKGD + ftbgn3p08.png 8-bit paletted, gray bKGD + ftbrn2c08.png 8-bit truecolor, red bKGD + ftbwn0g16.png 16-bit gray, white bKGD + ftbwn3p08.png 8-bit paletted, white bKGD + ftbyn3p08.png 8-bit paletted, yellow bKGD + ftp0n0g08.png 8-bit grayscale, opaque + ftp0n2c08.png 8-bit truecolor, opaque + ftp0n3p08.png 8-bit paletted, opaque + ftp1n3p08.png 8-bit paletted, no bKGD + +Here is the correct result of typing "pngtest -m bas*.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 + +October 1999 diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g01.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g01.png new file mode 100644 index 00000000000..e31e1c7a635 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g01.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g02.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g02.png new file mode 100644 index 00000000000..68809dd8fc0 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g02.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g04.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g04.png new file mode 100644 index 00000000000..6fa089cb8a4 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g04.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g08.png new file mode 100644 index 00000000000..bf522eef001 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g16.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g16.png new file mode 100644 index 00000000000..318ebcadf4f Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn0g16.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c08.png new file mode 100644 index 00000000000..21d2f91a868 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c16.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c16.png new file mode 100644 index 00000000000..1bd4a4d0e2c Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn2c16.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p01.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p01.png new file mode 100644 index 00000000000..a21db597746 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p01.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p02.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p02.png new file mode 100644 index 00000000000..1d0ab6197cc Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p02.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p04.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p04.png new file mode 100644 index 00000000000..6dc6eac83f3 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p04.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p08.png new file mode 100644 index 00000000000..0e07f483c0e Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn3p08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a08.png new file mode 100644 index 00000000000..3bb0dd06b51 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a16.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a16.png new file mode 100644 index 00000000000..6dbee9fbdb9 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn4a16.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a08.png new file mode 100644 index 00000000000..61062308548 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a16.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a16.png new file mode 100644 index 00000000000..a9bf3cb4612 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/basn6a16.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g01.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g01.png new file mode 100644 index 00000000000..ba746ffb2f5 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g01.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g02.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g02.png new file mode 100644 index 00000000000..3d83bd6900b Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g02.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g04.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g04.png new file mode 100644 index 00000000000..39a7050d27a Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn0g04.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn2c16.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn2c16.png new file mode 100644 index 00000000000..dd3168e5c86 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn2c16.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn3p08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn3p08.png new file mode 100644 index 00000000000..0ede3574db0 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbbn3p08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn2c16.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn2c16.png new file mode 100644 index 00000000000..85cec395c01 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn2c16.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn3p08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn3p08.png new file mode 100644 index 00000000000..8cf2e6fb6aa Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbgn3p08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbrn2c08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbrn2c08.png new file mode 100644 index 00000000000..5cca0d62104 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbrn2c08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn0g16.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn0g16.png new file mode 100644 index 00000000000..99bdeed2b3b Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn0g16.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn3p08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn3p08.png new file mode 100644 index 00000000000..eacab7a144c Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbwn3p08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbyn3p08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbyn3p08.png new file mode 100644 index 00000000000..656db0989ad Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftbyn3p08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n0g08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n0g08.png new file mode 100644 index 00000000000..333465fcdc9 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n0g08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n2c08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n2c08.png new file mode 100644 index 00000000000..fc6e42cb420 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n2c08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n3p08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n3p08.png new file mode 100644 index 00000000000..69a69e58722 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp0n3p08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp1n3p08.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp1n3p08.png new file mode 100644 index 00000000000..a6c9f35a862 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/pngsuite/ftp1n3p08.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/README.txt b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/README.txt new file mode 100644 index 00000000000..5ddae02ce9b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/README.txt @@ -0,0 +1,26 @@ +This directory (contrib/tools) contains tools used by the authors of libpng. + +Code and data placed in this directory is not required to build libpng, +however the code in this directory has been used to generate data or code in +the body of the libpng source. The source code identifies where this has +been done. Code in this directory may not compile on all operating systems +that libpng supports. + +NO COPYRIGHT RIGHTS ARE CLAIMED TO ANY OF THE FILES IN THIS DIRECTORY. + +To the extent possible under law, the authors have waived all copyright and +related or neighboring rights to this work. This work is published from: +United States. + +The files may be used freely in any way. + +The source code and comments in this directory are the original work of the +people named below. No other person or organization has made contributions to +the work in this directory. + +ORIGINAL AUTHORS + The following people have contributed to the code in this directory. None + of the people below claim any rights with regard to the contents of this + directory. + + John Bowler diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/checksum-icc.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/checksum-icc.c new file mode 100644 index 00000000000..581e7088a62 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/checksum-icc.c @@ -0,0 +1,102 @@ +/* checksum-icc.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Generate crc32 and adler32 checksums of the given input files, used to + * generate check-codes for use when matching ICC profiles within libpng. + */ +#include + +#include + +static int +read_one_file(FILE *ip, const char *name) +{ + uLong length = 0; + uLong a32 = adler32(0, NULL, 0); + uLong c32 = crc32(0, NULL, 0); + Byte header[132]; + + for (;;) + { + int ch = getc(ip); + Byte b; + + if (ch == EOF) break; + + b = (Byte)ch; + + if (length < sizeof header) + header[length] = b; + + ++length; + a32 = adler32(a32, &b, 1); + c32 = crc32(c32, &b, 1); + } + + if (ferror(ip)) + return 0; + + /* Success */ + printf("PNG_ICC_CHECKSUM(0x%8.8lx, 0x%8.8lx,\n PNG_MD5(" + "0x%2.2x%2.2x%2.2x%2.2x, 0x%2.2x%2.2x%2.2x%2.2x, 0x%2.2x%2.2x%2.2x%2.2x," + " 0x%2.2x%2.2x%2.2x%2.2x), %d,\n" + " \"%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d\", %lu, \"%s\")\n", + (unsigned long)a32, (unsigned long)c32, + header[84], header[85], header[86], header[87], + header[88], header[89], header[90], header[91], + header[92], header[93], header[94], header[95], + header[96], header[97], header[98], header[99], +# define u16(x) (header[x] * 256 + header[x+1]) +# define u32(x) (u16(x) * 65536 + u16(x+2)) + u32(64), u16(24), u16(26), u16(28), u16(30), u16(32), u16(34), + (unsigned long)length, name); + + return 1; +} + +int main(int argc, char **argv) +{ + int err = 0; + + printf("/* adler32, crc32, MD5[16], intent, date, length, file-name */\n"); + + if (argc > 1) + { + int i; + + for (i=1; i&0 4>&1 5>&2 + else + echo "chkfmt -e: EDITOR must be defined" >&2 + exit 1 + fi +} + +# Function to edit a single file - if the file isn't changed ask the user +# whether or not to continue. This stuff only works if the script is run from +# the command line (otherwise, don't specify -e or you will be sorry). +doed(){ + cp "$file" "$file".orig + "$EDITOR" "$file" 0>&3 1>&4 2>&5 3>&- 4>&- 5>&- || exit 1 + if cmp -s "$file".orig "$file" + then + rm "$file".orig + echo -n "$file: file not changed, type anything to continue: " >&5 + read ans 0>&3 + test -n "$ans" || return 1 + fi + return 0 +} + +# In beta versions the version string which appears in files can be a little +# long and cause spuriously overlong lines. To avoid this subtitute the version +# string with a 'standard' version a.b.cc before checking for long lines. +if test -r png.h +then + vers="`sed -n -e \ + 's/^#define PNG_LIBPNG_VER_STRING .\([0-9]\.[0-9]\.[0-9][0-9a-z]*\).$/\1/p' \ + png.h`" + echo "chkfmt: checking version $vers" +fi +if test -z "$vers" +then + echo "chkfmt: png.h not found, ignoring version number" >&2 +fi + +test -n "$1" || set -- . +find "$@" \( -type d \( -name '.git' -o -name '.libs' -o -name 'projects' \) \ + -prune \) -o \( -type f \ + ! -name '*.[oa]' ! -name '*.l[oa]' ! -name '*.png' ! -name '*.out' \ + ! -name '*.jpg' ! -name '*.patch' ! -name '*.obj' ! -name '*.exe' \ + ! -name '*.com' ! -name '*.tar.*' ! -name '*.zip' ! -name '*.ico' \ + ! -name '*.res' ! -name '*.rc' ! -name '*.mms' ! -name '*.rej' \ + ! -name '*.dsp' ! -name '*.orig' ! -name '*.dfn' ! -name '*.swp' \ + ! -name '~*' ! -name '*.3' \ + ! -name 'missing' ! -name 'mkinstalldirs' ! -name 'depcomp' \ + ! -name 'aclocal.m4' ! -name 'install-sh' ! -name 'Makefile.in' \ + ! -name 'ltmain.sh' ! -name 'config*' -print \) | { + st=0 + while read file + do + case "$file" in + *.mak|*[Mm]akefile.*|*[Mm]akefile) + # Makefiles require tabs, dependency lines can be this long. + check_tabs= + line_length=100;; + *.awk) + # Includes literal tabs + check_tabs= + # The following is arbitrary + line_length=132;; + *contrib/*/*.[ch]) + check_tabs=yes + line_length=96;; + *) + check_tabs=yes + line_length=80;; + esac + + # Note that vers can only contain 0-9, . and a-z + if test -n "$vers" + then + sed -e "s/$vers/a.b.cc/g" "$file" >"$file".$$ + else + cp "$file" "$file".$$ + fi + splt="`fold -$line_length "$file".$$ | diff -c "$file".$$ -`" + rm "$file".$$ + + if test -n "$splt" + then + echo "$file: lines too long" + st=1 + if test -n "$EDITOR" -a -n "$edit" + then + doed "$file" || exit 1 + elif test -n "$verbose" + then + echo "$splt" + fi + fi + if test -n "$check_tabs" + then + tab="`tr -c -d '\t' <"$file"`" + if test -n "$tab" + then + echo "$file: file contains tab characters" + st=1 + if test -n "$EDITOR" -a -n "$edit" + then + doed "$file" || exit 1 + elif test -n "$verbose" + then + echo "$splt" + fi + fi + fi + done + exit $st +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/cvtcolor.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/cvtcolor.c new file mode 100644 index 00000000000..e6793c7d596 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/cvtcolor.c @@ -0,0 +1,188 @@ +/*- + * convert.c + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Convert 8-bit sRGB or 16-bit linear values to another format. + */ +#define _ISOC99_SOURCE 1 + +#include +#include +#include +#include + +#include + +#include "sRGB.h" + +static void +usage(const char *prog) +{ + fprintf(stderr, + "%s: usage: %s [-linear|-sRGB] [-gray|-color] component{1,4}\n", + prog, prog); + exit(1); +} + +unsigned long +component(const char *prog, const char *arg, int issRGB) +{ + char *ep; + unsigned long c = strtoul(arg, &ep, 0); + + if (ep <= arg || *ep || c > 65535 || (issRGB && c > 255)) + { + fprintf(stderr, "%s: %s: invalid component value (%lu)\n", prog, arg, c); + usage(prog); + } + + return c; +} + +int +main(int argc, const char **argv) +{ + const char *prog = *argv++; + int to_linear = 0, to_gray = 0, to_color = 0; + int channels = 0; + double c[4]; + + /* FE_TONEAREST is the IEEE754 round to nearest, preferring even, mode; i.e. + * everything rounds to the nearest value except that '.5' rounds to the + * nearest even value. + */ + fesetround(FE_TONEAREST); + + c[3] = c[2] = c[1] = c[0] = 0; + + while (--argc > 0 && **argv == '-') + { + const char *arg = 1+*argv++; + + if (strcmp(arg, "sRGB") == 0) + to_linear = 0; + + else if (strcmp(arg, "linear") == 0) + to_linear = 1; + + else if (strcmp(arg, "gray") == 0) + to_gray = 1, to_color = 0; + + else if (strcmp(arg, "color") == 0) + to_gray = 0, to_color = 1; + + else + usage(prog); + } + + switch (argc) + { + default: + usage(prog); + break; + + case 4: + c[3] = component(prog, argv[3], to_linear); + ++channels; + case 3: + c[2] = component(prog, argv[2], to_linear); + ++channels; + case 2: + c[1] = component(prog, argv[1], to_linear); + ++channels; + case 1: + c[0] = component(prog, argv[0], to_linear); + ++channels; + break; + } + + if (to_linear) + { + int i; + int components = channels; + + if ((components & 1) == 0) + --components; + + for (i=0; i 0) + for (i=0; i 2) + { + fprintf(stderr, "%s: too many channels (%d) for -color\n", + prog, channels); + usage(prog); + } + + c[3] = c[1]; /* alpha, if present */ + c[2] = c[1] = c[0]; + } + + if (to_linear) + { + int i; + if ((channels & 1) == 0) + { + double alpha = c[channels-1]; + for (i=0; i= 0) + c[i] = sRGB_from_linear(c[i]); + + for (i=0; i + +/* fixitxt version 1.0.0 + * + * Copyright 2013 Glenn Randers-Pehrson + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Usage: + * + * fixitxt.exe < bad.png > good.png + * + * Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more + * uncompressed iTXt chunks. Assumes that the actual length is greater + * than or equal to the value in the length byte, and that the CRC is + * correct for the actual length. This program hunts for the CRC and + * adjusts the length byte accordingly. It is not an error to process a + * PNG file that has no iTXt chunks or one that has valid iTXt chunks; + * such files will simply be copied. + * + * Requires zlib (for crc32 and Z_NULL); build with + * + * gcc -O -o fixitxt fixitxt.c -lz + */ + +#define MAX_LENGTH 500000 + +#define GETBREAK c=getchar(); if (c == EOF) break; +#include + +main() +{ + unsigned int i; + unsigned char buf[MAX_LENGTH]; + unsigned long crc; + unsigned int c; + +/* Skip 8-byte signature */ + for (i=8; i; i--) + { + c=GETBREAK; + putchar(c); + } + +if (c != EOF) +for (;;) + { + /* Read the length */ + unsigned long length; + c=GETBREAK; buf[0] = c; + c=GETBREAK; buf[1] = c; + c=GETBREAK; buf[2] = c; + c=GETBREAK; buf[3] = c; + + length=((((unsigned long) buf[0]<<8 + buf[1]<<16) + buf[2] << 8) + buf[3]); + /* Read the chunkname */ + c=GETBREAK; buf[4] = c; + c=GETBREAK; buf[5] = c; + c=GETBREAK; buf[6] = c; + c=GETBREAK; buf[7] = c; + + + /* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */ + if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116) + { + if (length >= MAX_LENGTH-12) + break; /* To do: handle this more gracefully */ + + /* Initialize the CRC */ + crc = crc32(0, Z_NULL, 0); + + /* Copy the data bytes */ + for (i=8; i < length + 12; i++) + { + c=GETBREAK; buf[i] = c; + } + + /* Calculate the CRC */ + crc = crc32(crc, buf+4, (uInt)length+4); + + for (;;) + { + /* Check the CRC */ + if (((crc >> 24) & 0xff) == buf[length+8] && + ((crc >> 16) & 0xff) == buf[length+9] && + ((crc >> 8) & 0xff) == buf[length+10] && + ((crc ) & 0xff) == buf[length+11]) + break; + + length++; + + if (length >= MAX_LENGTH-12) + break; + + c=GETBREAK; + buf[length+11]=c; + + /* Update the CRC */ + crc = crc32(crc, buf+7+length, 1); + } + + /* Update length bytes */ + buf[0] = (length << 24) & 0xff; + buf[1] = (length << 16) & 0xff; + buf[2] = (length << 8) & 0xff; + buf[3] = (length ) & 0xff; + + /* Write the fixed iTXt chunk (length, name, data, crc) */ + for (i=0; i= 80) { + print str "," + str = " " $0 "U" + } else + str = t + } + END{ + print str + }' +} +# +# The logarithm table. +cat <= 2^32) x = 2^32-1; + x; +} +END +echo '};' +echo +# +# And the table of adjustment values. +cat <=0;--i){ + (1 - e(-(2^i)/65536*l(2))) * 2^(32-i) +} +END +echo '#endif' diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/makesRGB.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/makesRGB.c new file mode 100644 index 00000000000..e66c9f1576b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/makesRGB.c @@ -0,0 +1,430 @@ +/* makesRGB.c -- build sRGB-to-linear and linear-to-sRGB conversion tables + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Make a table to convert 8-bit sRGB encoding values into the closest 16-bit + * linear value. + * + * Make two tables to take a linear value scaled to 255*65535 and return an + * approximation to the 8-bit sRGB encoded value. Calculate the error in these + * tables and display it. + */ +#define _C99_SOURCE 1 +#include +#include +#include + +/* pngpriv.h includes the definition of 'PNG_sRGB_FROM_LINEAR' which is required + * to verify the actual code. + */ +#include "../../pngpriv.h" + +#include "sRGB.h" + +/* The tables are declared 'const' in pngpriv.h, so this redefines the tables to + * be used. + */ +#define png_sRGB_table sRGB_table +#define png_sRGB_base sRGB_base +#define png_sRGB_delta sRGB_delta + +static png_uint_16 png_sRGB_table[256]; +static png_uint_16 png_sRGB_base[512]; +static png_byte png_sRGB_delta[512]; + +static const unsigned int max_input = 255*65535; + +double +fsRGB(double l) +{ + return sRGB_from_linear(l/max_input); +} + +double +sRGB(unsigned int i) +{ + return fsRGB(i); +} + +double +finvsRGB(unsigned int i) +{ + return 65535 * linear_from_sRGB(i/255.); +} + +png_uint_16 +invsRGB(unsigned int i) +{ + unsigned int x = nearbyint(finvsRGB(i)); + + if (x > 65535) + { + fprintf(stderr, "invsRGB(%u) overflows to %u\n", i, x); + exit(1); + } + + return (png_uint_16)x; +} + +int +main(int argc, char **argv) +{ + unsigned int i, i16, ibase; + double min_error = 0; + double max_error = 0; + double min_error16 = 0; + double max_error16 = 0; + double adjust; + double adjust_lo = 0.4, adjust_hi = 0.6, adjust_mid = 0.5; + unsigned int ec_lo = 0, ec_hi = 0, ec_mid = 0; + unsigned int error_count = 0; + unsigned int error_count16 = 0; + int test_only = 0; + + if (argc > 1) + test_only = strcmp("--test", argv[1]) == 0; + + /* Initialize the encoding table first. */ + for (i=0; i<256; ++i) + { + png_sRGB_table[i] = invsRGB(i); + } + + /* Now work out the decoding tables (this is where the error comes in because + * there are 512 set points and 512 straight lines between them.) + */ + for (;;) + { + if (ec_lo == 0) + adjust = adjust_lo; + + else if (ec_hi == 0) + adjust = adjust_hi; + + else if (ec_mid == 0) + adjust = adjust_mid; + + else if (ec_mid < ec_hi) + adjust = (adjust_mid + adjust_hi)/2; + + else if (ec_mid < ec_lo) + adjust = (adjust_mid + adjust_lo)/2; + + else + { + fprintf(stderr, "not reached: %u .. %u .. %u\n", ec_lo, ec_mid, ec_hi); + exit(1); + } + + /* Calculate the table using the current 'adjust' */ + for (i=0; i<=511; ++i) + { + double lo = 255 * sRGB(i << 15); + double hi = 255 * sRGB((i+1) << 15); + unsigned int calc; + + calc = nearbyint((lo+adjust) * 256); + if (calc > 65535) + { + fprintf(stderr, "table[%d][0]: overflow %08x (%d)\n", i, calc, + calc); + exit(1); + } + png_sRGB_base[i] = calc; + + calc = nearbyint((hi-lo) * 32); + if (calc > 255) + { + fprintf(stderr, "table[%d][1]: overflow %08x (%d)\n", i, calc, + calc); + exit(1); + } + png_sRGB_delta[i] = calc; + } + + /* Check the 16-bit linear values alone: */ + error_count16 = 0; + for (i16=0; i16 <= 65535; ++i16) + { + unsigned int i = 255*i16; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + ++error_count16; + } + + /* Now try changing the adjustment. */ + if (ec_lo == 0) + ec_lo = error_count16; + + else if (ec_hi == 0) + ec_hi = error_count16; + + else if (ec_mid == 0) + { + ec_mid = error_count16; + printf("/* initial error counts: %u .. %u .. %u */\n", ec_lo, ec_mid, + ec_hi); + } + + else if (error_count16 < ec_mid) + { + printf("/* adjust (mid ): %f: %u -> %u */\n", adjust, ec_mid, + error_count16); + ec_mid = error_count16; + adjust_mid = adjust; + } + + else if (adjust < adjust_mid && error_count16 < ec_lo) + { + printf("/* adjust (low ): %f: %u -> %u */\n", adjust, ec_lo, + error_count16); + ec_lo = error_count16; + adjust_lo = adjust; + } + + else if (adjust > adjust_mid && error_count16 < ec_hi) + { + printf("/* adjust (high): %f: %u -> %u */\n", adjust, ec_hi, + error_count16); + ec_hi = error_count16; + adjust_hi = adjust; + } + + else + { + adjust = adjust_mid; + printf("/* adjust: %f: %u */\n", adjust, ec_mid); + break; + } + } + + /* For each entry in the table try to adjust it to minimize the error count + * in that entry. Each entry corresponds to 128 input values. + */ + for (ibase=0; ibase<65536; ibase+=128) + { + png_uint_16 base = png_sRGB_base[ibase >> 7], trybase = base, ob=base; + png_byte delta = png_sRGB_delta[ibase >> 7], trydelta = delta, od=delta; + unsigned int ecbase = 0, eco; + + for (;;) + { + png_sRGB_base[ibase >> 7] = trybase; + png_sRGB_delta[ibase >> 7] = trydelta; + + /* Check the 16-bit linear values alone: */ + error_count16 = 0; + for (i16=ibase; i16 < ibase+128; ++i16) + { + unsigned int i = 255*i16; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + ++error_count16; + } + + if (error_count16 == 0) + break; + + if (ecbase == 0) + { + eco = ecbase = error_count16; + ++trybase; /* First test */ + } + + else if (error_count16 < ecbase) + { + if (trybase > base) + { + base = trybase; + ++trybase; + } + else if (trybase < base) + { + base = trybase; + --trybase; + } + else if (trydelta > delta) + { + delta = trydelta; + ++trydelta; + } + else if (trydelta < delta) + { + delta = trydelta; + --trydelta; + } + else + { + fprintf(stderr, "makesRGB: impossible\n"); + exit(1); + } + ecbase = error_count16; + } + + else + { + if (trybase > base) + trybase = base-1; + else if (trybase < base) + { + trybase = base; + ++trydelta; + } + else if (trydelta > delta) + trydelta = delta-1; + else if (trydelta < delta) + break; /* end of tests */ + } + } + + png_sRGB_base[ibase >> 7] = base; + png_sRGB_delta[ibase >> 7] = delta; + if (base != ob || delta != od) + { + printf("/* table[%u]={%u,%u} -> {%u,%u} %u -> %u errors */\n", + ibase>>7, ob, od, base, delta, eco, ecbase); + } + else if (0) + printf("/* table[%u]={%u,%u} %u errors */\n", ibase>>7, ob, od, + ecbase); + } + + /* Only do the full (slow) test at the end: */ + min_error = -.4999; + max_error = .4999; + error_count = 0; + + for (i=0; i <= max_input; ++i) + { + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + { + double err = 255*sRGB(i) - icalc; + + if (err > (max_error+.001) || err < (min_error-.001)) + { + printf( + "/* 0x%08x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n", + i, iexact, icalc, png_sRGB_base[i>>15], + png_sRGB_delta[i>>15], err); + } + + ++error_count; + if (err > max_error) + max_error = err; + else if (err < min_error) + min_error = err; + } + } + + /* Re-check the 16-bit cases too, including the warning if there is an error + * bigger than 1. + */ + error_count16 = 0; + max_error16 = 0; + min_error16 = 0; + for (i16=0; i16 <= 65535; ++i16) + { + unsigned int i = 255*i16; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + { + double err = 255*sRGB(i) - icalc; + + ++error_count16; + if (err > max_error16) + max_error16 = err; + else if (err < min_error16) + min_error16 = err; + + if (abs(icalc - iexact) > 1) + printf( + "/* 0x%04x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n", + i16, iexact, icalc, png_sRGB_base[i>>15], + png_sRGB_delta[i>>15], err); + } + } + + /* Check the round trip for each 8-bit sRGB value. */ + for (i16=0; i16 <= 255; ++i16) + { + unsigned int i = 255 * png_sRGB_table[i16]; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (i16 != iexact) + { + fprintf(stderr, "8-bit rounding error: %d -> %d\n", i16, iexact); + exit(1); + } + + if (icalc != i16) + { + double finv = finvsRGB(i16); + + printf("/* 8-bit roundtrip error: %d -> %f -> %d(%f) */\n", + i16, finv, icalc, fsRGB(255*finv)); + } + } + + + printf("/* error: %g - %g, %u (%g%%) of readings inexact */\n", + min_error, max_error, error_count, (100.*error_count)/max_input); + printf("/* 16-bit error: %g - %g, %u (%g%%) of readings inexact */\n", + min_error16, max_error16, error_count16, (100.*error_count16)/65535); + + if (!test_only) + { + printf("PNG_CONST png_uint_16 png_sRGB_table[256] =\n{\n "); + for (i=0; i<255; ) + { + do + { + printf("%d,", png_sRGB_table[i++]); + } + while ((i & 0x7) != 0 && i<255); + if (i<255) printf("\n "); + } + printf("%d\n};\n\n", png_sRGB_table[i]); + + + printf("PNG_CONST png_uint_16 png_sRGB_base[512] =\n{\n "); + for (i=0; i<511; ) + { + do + { + printf("%d,", png_sRGB_base[i++]); + } + while ((i & 0x7) != 0 && i<511); + if (i<511) printf("\n "); + } + printf("%d\n};\n\n", png_sRGB_base[i]); + + printf("PNG_CONST png_byte png_sRGB_delta[512] =\n{\n "); + for (i=0; i<511; ) + { + do + { + printf("%d,", png_sRGB_delta[i++]); + } + while ((i & 0xf) != 0 && i<511); + if (i<511) printf("\n "); + } + printf("%d\n};\n\n", png_sRGB_delta[i]); + } + + return 0; +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/sRGB.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/sRGB.h new file mode 100644 index 00000000000..22c8f7c0e3d --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/tools/sRGB.h @@ -0,0 +1,48 @@ +/*- + * sRGB.h + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Utility file; not actually a header, this contains definitions of sRGB + * calculation functions for inclusion in those test programs that need them. + * + * All routines take and return a floating point value in the range + * 0 to 1.0, doing a calculation according to the sRGB specification + * (in fact the source of the numbers is the wikipedia article at + * http://en.wikipedia.org/wiki/SRGB). + */ +static double +sRGB_from_linear(double l) +{ + if (l <= 0.0031308) + l *= 12.92; + + else + l = 1.055 * pow(l, 1/2.4) - 0.055; + + return l; +} + +static double +linear_from_sRGB(double s) +{ + if (s <= 0.04045) + return s / 12.92; + + else + return pow((s+0.055)/1.055, 2.4); +} + +static double +YfromRGB(double r, double g, double b) +{ + /* Use the sRGB (rounded) coefficients for Rlinear, Glinear, Blinear to get + * the CIE Y value (also linear). + */ + return 0.2126 * r + 0.7152 * g + 0.0722 * b; +} diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.c new file mode 100644 index 00000000000..dcde18a3af4 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.c @@ -0,0 +1,451 @@ +/*------------------------------------- + * PNGFILE.C -- Image File Functions + *------------------------------------- + * + * Copyright 2000, Willem van Schaik. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include +#include +#include +#include +#include + +#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) + ; +#ifdef PNG_CONSOLE_IO_SUPPORTED + 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_sig_cmp(pbSig, 0, 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 */ + +#ifdef PNG_STDIO_SUPPORTED + 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 */ + /* let the library process alpha, transparency, background, etc. */ + +#ifdef PNG_READ_16_TO_8_SUPPORTED + if (iBitDepth == 16) +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +# else + png_set_strip_16(png_ptr); +# endif +#endif + 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 are 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 */ + +#ifdef PNG_STDIO_SUPPORTED + 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; +} + +#ifndef PNG_STDIO_SUPPORTED + +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/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.h new file mode 100644 index 00000000000..474426c22ea --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/PngFile.h @@ -0,0 +1,30 @@ +/*------------------------------------------*/ +/* PNGFILE.H -- Header File for pngfile.c*/ +/*------------------------------------------*/ + +/* Copyright 2000, Willem van Schaik.*/ + +/* This code is released under the libpng license.*/ +/* For conditions of distribution and use, see the disclaimer*/ +/* and license in png.h*/ + +#include +#include +#include +#include + +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); + +#ifndef PNG_STDIO_SUPPORTED +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/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/README.txt b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/README.txt new file mode 100644 index 00000000000..72c5cba1790 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/README.txt @@ -0,0 +1,61 @@ +Microsoft Developer Studio Build File, Format Version 6.00 for VisualPng +------------------------------------------------------------------------ + +Copyright 2000, Willem van Schaik. + +This code is released under the libpng license. +For conditions of distribution and use, see the disclaimer +and license 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/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.c b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.c new file mode 100644 index 00000000000..236525a59fe --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.c @@ -0,0 +1,970 @@ +/*------------------------------------ + * VisualPng.C -- Shows a PNG image + *------------------------------------ + * + * Copyright 2000, Willem van Schaik. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license 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 +#include +#include +#include +#include + +/* 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 mathematically 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/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.dsp b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.dsp new file mode 100644 index 00000000000..741ef6ce76f --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /I "..\.." /I "..\..\..\zlib" /D "WIN32" /D "NDEBUG" /D "PNG_NO_STDIO" /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" /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" /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/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.dsw b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.dsw new file mode 100644 index 00000000000..a30e1cc1cdb --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.ico b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.ico new file mode 100644 index 00000000000..68aa3719fb5 Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.ico differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.png b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.png new file mode 100644 index 00000000000..c6aa80a9bfa Binary files /dev/null and b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.png differ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.rc b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/VisualPng.rc new file mode 100644 index 00000000000..6e0623a73cf --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/cexcept.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/cexcept.h new file mode 100644 index 00000000000..5f45d769758 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/cexcept.h @@ -0,0 +1,248 @@ +/*=== +cexcept.h 2.0.1 (2008-Jul-19-Sat) +http://www.nicemice.net/cexcept/ +Adam M. Costello +http://www.nicemice.net/amc/ + +An interface for exception-handling in ANSI C (C89 and subsequent ISO +standards), developed jointly with Cosmin Truta. + + Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta. + This software may be modified only if its author and version + information is updated accurately, and may be redistributed + only if accompanied by this unaltered notice. Subject to those + restrictions, permission is granted to anyone to do anything + with this software. The copyright holders make no guarantees + regarding this software, and are not responsible for any damage + resulting from its use. + +The cexcept interface is not compatible with and cannot interact +with system exceptions (like division by zero or memory segmentation +violation), compiler-generated exceptions (like C++ exceptions), or +other exception-handling interfaces. + +When using this interface across multiple .c files, do not 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). The .c files should then 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 + +#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) { \ + do + +#define exception__catch(action) \ + while (the_exception_context->caught = 0, \ + the_exception_context->caught); \ + } \ + 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 do, and Catch begins with while(0) and ends with */ +/* else, to ensure that Try/Catch syntax is similar to if/else */ +/* syntax. */ +/* */ +/* The 0 in while(0) is expressed as x=0,x in order to appease */ +/* compilers that warn about constant expressions inside while(). */ +/* Most compilers should still recognize that the condition is always */ +/* false and avoid generating code for it. */ + +#define Throw \ + for (;; longjmp(*the_exception_context->penv, 1)) \ + the_exception_context->v.etmp = + + +#endif /* CEXCEPT_H */ diff --git a/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/resource.h b/Build/source/libs/libpng/libpng-1.6.2/contrib/visupng/resource.h new file mode 100644 index 00000000000..b62176d1dca --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.2/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 -- cgit v1.2.3