diff -ru4NwbB libpng-1.5.4/Makefile.am libpng-1.5.5beta07/Makefile.am --- libpng-1.5.4/Makefile.am 2011-07-07 06:24:55.914993260 -0500 +++ libpng-1.5.5beta07/Makefile.am 2011-09-08 12:21:40.706859428 -0500 @@ -44,9 +44,14 @@ -version-number @PNGLIB_MAJOR@@PNGLIB_MINOR@:@PNGLIB_RELEASE@:0 if HAVE_LD_VERSION_SCRIPT # Versioned symbols and restricted exports +if HAVE_SOLARIS_LD + libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_LDFLAGS += -Wl,-M Wl,libpng.vers +else libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_LDFLAGS += -Wl,--version-script=libpng.vers +endif + libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_DEPENDENCIES = libpng.vers else # Only restricted exports when possible libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_LDFLAGS += -export-symbols libpng.sym @@ -96,9 +101,9 @@ $(PNGLIB_BASENAME)-config: libpng-config cp libpng-config $@ scripts/sym.out scripts/vers.out: png.h pngconf.h pnglibconf.h -scripts/symbols.out: png.h pngconf.h scripts/pnglibconf.h.prebuilt +scripts/symbols.out: png.h pngconf.h $(srcdir)/scripts/pnglibconf.h.prebuilt libpng.sym: scripts/sym.out rm -f $@ cp $? $@ @@ -107,9 +112,10 @@ cp $? $@ pnglibconf.h: pnglibconf.out rm -f $@ cp $? $@ -scripts/pnglibconf.h.prebuilt: +$(srcdir)/scripts/pnglibconf.h.prebuilt: + @echo "Attempting to build $@" >&2 @echo "This is a machine generated file, but if you want to make" >&2 @echo "a new one simply make 'scripts/pnglibconf.out' and copy that" >&2 @exit 1 @@ -118,10 +124,10 @@ # 'make test' is the first thing the user does.) pngvalid.o pngtest.o: pnglibconf.h # We must use -DPNG_NO_USE_READ_MACROS here even when the library may actually -# be built with PNG_USE_READ_MACROS; this stops the read macros interfering -# with the symbol file format. +# be built with PNG_USE_READ_MACROS; this prevents the read macros from +# interfering with the symbol file format. SYMBOL_CFLAGS = -DPNGLIB_LIBNAME='PNG@PNGLIB_MAJOR@@PNGLIB_MINOR@_0'\ -DPNGLIB_VERSION='@PNGLIB_VERSION@'\ -DSYMBOL_PREFIX='$(SYMBOL_PREFIX)'\ -DPNG_NO_USE_READ_MACROS -DPNG_BUILDING_SYMBOL_TABLE @@ -161,9 +167,9 @@ rm -f $@ dfn?.out test -z "$(CPPFLAGS)" echo "com @PNGLIB_VERSION@ STANDARD API DEFINITION" |\ $(AWK) -f ${srcdir}/scripts/options.awk out=dfn1.out\ - logunsupported=4 - ${srcdir}/scripts/pnglibconf.dfa 1>&2 + logunsupported=1 - ${srcdir}/scripts/pnglibconf.dfa 1>&2 $(AWK) -f ${srcdir}/scripts/options.awk out=dfn2.out dfn1.out 1>&2 rm dfn1.out mv dfn2.out $@ diff -ru4NwbB libpng-1.5.4/configure.ac libpng-1.5.5beta07/configure.ac --- libpng-1.5.4/configure.ac 2011-07-07 06:24:55.921495804 -0500 +++ libpng-1.5.5beta07/configure.ac 2011-09-08 12:21:40.713902457 -0500 @@ -103,9 +103,26 @@ have_ld_version_script=no AC_MSG_RESULT(no) ;; * ) + +AC_MSG_CHECKING([if using Solaris linker]) +SLD=`$LD --version 2>&1 | grep Solaris` +if test "$SLD"; then + have_solaris_ld=yes + AC_MSG_RESULT(yes) +else + have_solaris_ld=no + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(HAVE_SOLARIS_LD, test "$have_solaris_ld" = "yes") + +if test "$have_solaris_ld" = "yes"; then + GLD=`$LD --help < /dev/null 2>&1 | grep 'M mapfile'` +else GLD=`$LD --help < /dev/null 2>/dev/null | grep version-script` +fi + if test "$GLD"; then have_ld_version_script=yes AC_MSG_RESULT(yes) else diff -ru4NwbB libpng-1.5.4/contrib/pngminus/makefile.std libpng-1.5.5beta07/contrib/pngminus/makefile.std --- libpng-1.5.4/contrib/pngminus/makefile.std 2011-07-07 06:24:48.716051405 -0500 +++ libpng-1.5.5beta07/contrib/pngminus/makefile.std 2011-09-08 12:21:33.981488109 -0500 @@ -7,11 +7,11 @@ RM=rm -f #PNGPATH = /usr/local -#PNGINC = -I$(PNGPATH)/include/libpng12 -#PNGLIB = -L$(PNGPATH)/lib -lpng12 -#PNGLIBS = $(PNGPATH)/lib/libpng12.a +#PNGINC = -I$(PNGPATH)/include/libpng15 +#PNGLIB = -L$(PNGPATH)/lib -lpng15 +#PNGLIBS = $(PNGPATH)/lib/libpng15.a PNGINC = -I../.. PNGLIB = -L../.. -lpng PNGLIBS = ../../libpng.a @@ -22,11 +22,11 @@ ZINC = -I../../../zlib ZLIB = -L../../../zlib -lz ZLIBS = ../../../zlib/libz.a -CFLAGS=-O3 $(PNGINC) $(ZINC) -LDFLAGS=$(PNGLIB) $(ZLIB) -LDFLAGSS=$(PNGLIBS) $(ZLIBS) +CFLAGS=$(PNGINC) $(ZINC) +LDLIBS=$(PNGLIB) $(ZLIB) +LDLIBSS=$(PNGLIBS) $(ZLIBS) C=.c O=.o L=.a E= @@ -39,21 +39,21 @@ png2pnm$(O): png2pnm$(C) $(CC) -c $(CFLAGS) png2pnm$(C) png2pnm$(E): png2pnm$(O) - $(LD) -o png2pnm$(E) png2pnm$(O) $(LDFLAGS) -lm + $(LD) $(LDFLAGS) -o png2pnm$(E) png2pnm$(O) $(LDLIBS) -lm png2pnm-static$(E): png2pnm$(O) - $(LD) -o png2pnm-static$(E) png2pnm$(O) $(LDFLAGSS) -lm + $(LD) $(LDFLAGS) -o png2pnm-static$(E) png2pnm$(O) $(LDLIBSS) -lm pnm2png$(O): pnm2png$(C) $(CC) -c $(CFLAGS) pnm2png$(C) pnm2png$(E): pnm2png$(O) - $(LD) -o pnm2png$(E) pnm2png$(O) $(LDFLAGS) -lm + $(LD) $(LDFLAGS) -o pnm2png$(E) pnm2png$(O) $(LDLIBS) -lm pnm2png-static$(E): pnm2png$(O) - $(LD) -o pnm2png-static$(E) pnm2png$(O) $(LDFLAGSS) -lm + $(LD) $(LDFLAGS) -o pnm2png-static$(E) pnm2png$(O) $(LDLIBSS) -lm clean: $(RM) png2pnm$(O) $(RM) pnm2png$(O) diff -ru4NwbB libpng-1.5.4/contrib/visupng/PngFile.c libpng-1.5.5beta07/contrib/visupng/PngFile.c --- libpng-1.5.4/contrib/visupng/PngFile.c 2011-06-17 19:51:31.373093000 -0500 +++ libpng-1.5.5beta07/contrib/visupng/PngFile.c 2011-09-03 09:35:07.323726000 -0500 @@ -1,13 +1,14 @@ -//------------------------------------- -// 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 +/*------------------------------------- + * 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 @@ -27,9 +28,9 @@ static png_structp png_ptr = NULL; static png_infop info_ptr = NULL; -// cexcept interface +/* cexcept interface */ static void png_cexcept_error(png_structp png_ptr, png_const_charp msg) { @@ -42,9 +43,9 @@ Throw msg; } } -// Windows open-file functions +/* Windows open-file functions */ void PngFileInitialize (HWND hwnd) { static TCHAR szFilter[] = TEXT ("PNG Files (*.PNG)\0*.png\0") @@ -56,15 +57,15 @@ ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; - ofn.lpstrFile = NULL; // Set in Open and Close functions + ofn.lpstrFile = NULL; /* Set in Open and Close functions */ ofn.nMaxFile = MAX_PATH; - ofn.lpstrFileTitle = NULL; // Set in Open and Close functions + 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.Flags = 0; /* Set in Open and Close functions */ ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = TEXT ("png"); ofn.lCustData = 0; @@ -91,9 +92,9 @@ return GetSaveFileName (&ofn); } -// PNG image handler functions +/* PNG image handler functions */ BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData, int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor) { @@ -108,9 +109,9 @@ png_byte *pbImageData = *ppbImageData; static png_byte **ppbRowPointers = NULL; int i; - // open the PNG input file + /* open the PNG input file */ if (!pstrFileName) { *ppbImageData = pbImageData = NULL; @@ -122,18 +123,18 @@ *ppbImageData = pbImageData = NULL; return FALSE; } - // first check the eight byte PNG signature + /* 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 + /* 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) @@ -152,9 +153,9 @@ Try { - // initialize the png structure + /* initialize the png structure */ #ifdef PNG_STDIO_SUPPORTED png_init_io(png_ptr, pfFile); #else @@ -162,19 +163,19 @@ #endif png_set_sig_bytes(png_ptr, 8); - // read all PNG info up to image data + /* read all PNG info up to image data */ png_read_info(png_ptr, info_ptr); - // get width, height, bit-depth and color-type + /* get width, height, bit-depth and color-type */ png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth, &iColorType, NULL, NULL, NULL); - // expand images of all color-type and bit-depth to 3x8 bit RGB images - // let the library process things like alpha, transparency, background + /* 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 @@ -192,9 +193,9 @@ 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. + /* 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; @@ -205,30 +206,30 @@ { pBkgColor = NULL; } - // if required set gamma conversion + /* if required set gamma conversion */ if (png_get_gAMA(png_ptr, info_ptr, &dGamma)) png_set_gamma(png_ptr, (double) 2.2, dGamma); - // after the transformations have been registered update info_ptr data + /* 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 + /* 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 + /* 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 + /* now we can allocate memory to store the image */ if (pbImageData) { free (pbImageData); @@ -240,35 +241,35 @@ png_error(png_ptr, "Visual PNG: out of memory"); } *ppbImageData = pbImageData; - // and allocate memory for an array of row-pointers + /* 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 + /* 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 + /* 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) + /* read the additional chunks in the PNG file (not really needed) */ png_read_end(png_ptr, NULL); - // and we're done + /* and we're done */ free (ppbRowPointers); ppbRowPointers = NULL; - // yepp, done + /* yepp, done */ } Catch (msg) { @@ -300,17 +301,17 @@ png_uint_32 ulRowBytes; static png_byte **ppbRowPointers = NULL; int i; - // open the PNG output file + /* open the PNG output file */ if (!pstrFileName) return FALSE; if (!(pfFile = fopen(pstrFileName, "wb"))) return FALSE; - // prepare the standard PNG structures + /* 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) @@ -327,62 +328,62 @@ } Try { - // initialize the png structure + /* 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 + /* 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 + /* write the file header information */ png_write_info(png_ptr, info_ptr); - // swap the BGR pixels in the DiData structure to RGB + /* swap the BGR pixels in the DiData structure to RGB */ png_set_bgr(png_ptr); - // row_bytes is the width x number of channels + /* row_bytes is the width x number of channels */ ulRowBytes = iWidth * ciChannels; - // we can allocate memory for an array of row-pointers + /* 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 + /* 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 + /* 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) + /* write the additional chunks to the PNG file (not really needed) */ png_write_end(png_ptr, info_ptr); - // and we're done + /* and we're done */ free (ppbRowPointers); ppbRowPointers = NULL; - // clean up after the write, and free any memory allocated + /* clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - // yepp, done + /* yepp, done */ } Catch (msg) { @@ -442,7 +443,8 @@ } #endif -//----------------- -// end of source -//----------------- +/*----------------- + * end of source + *----------------- + */ diff -ru4NwbB libpng-1.5.4/contrib/visupng/PngFile.h libpng-1.5.5beta07/contrib/visupng/PngFile.h --- libpng-1.5.4/contrib/visupng/PngFile.h 2009-08-31 08:27:35.000000000 -0500 +++ libpng-1.5.5beta07/contrib/visupng/PngFile.h 2011-09-03 09:14:15.798153000 -0500 @@ -1,13 +1,13 @@ -//------------------------------------------ -// 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 +/*------------------------------------------*/ +/* 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 diff -ru4NwbB libpng-1.5.4/contrib/visupng/VisualPng.c libpng-1.5.5beta07/contrib/visupng/VisualPng.c --- libpng-1.5.4/contrib/visupng/VisualPng.c 2011-05-07 10:39:43.718665000 -0500 +++ libpng-1.5.5beta07/contrib/visupng/VisualPng.c 2011-09-03 09:23:17.727992000 -0500 @@ -1,42 +1,43 @@ -//------------------------------------ -// VisualPng.C -- Shows a PNG image -//------------------------------------ +/*------------------------------------ + * 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 + */ -// Copyright 2000, Willem van Schaik. +/* switches */ -// This code is released under the libpng license. -// For conditions of distribution and use, see the disclaimer -// and license in png.h - -// switches - -// defines +/* defines */ #define PROGNAME "VisualPng" #define LONGNAME "Win32 Viewer for PNG-files" #define VERSION "1.0 of 2000 June 07" -// constants +/* constants */ #define MARGIN 8 -// standard includes +/* standard includes */ #include #include #include #include -// application includes +/* application includes */ #include "png.h" #include "pngfile.h" #include "resource.h" -// macros +/* macros */ -// function prototypes +/* function prototypes */ LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ; @@ -64,16 +65,16 @@ BYTE *pDiData, int cxWinSize, int cyWinSize, BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels, BOOL bStretched); -// a few global variables +/* a few global variables */ static char *szProgName = PROGNAME; static char *szAppName = LONGNAME; static char *szIconName = PROGNAME; static char szCmdFileName [MAX_PATH]; -// MAIN routine +/* MAIN routine */ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { @@ -89,9 +90,9 @@ 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.hbrBackground = NULL; /* (HBRUSH) GetStockObject (GRAY_BRUSH); */ wndclass.lpszMenuName = szProgName; wndclass.lpszClassName = szProgName; if (!RegisterClass (&wndclass)) @@ -100,18 +101,18 @@ szProgName, MB_ICONERROR); return 0; } - // if filename given on commandline, store it + /* 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 + /* calculate size of window-borders */ ixBorders = 2 * (GetSystemMetrics (SM_CXBORDER) + GetSystemMetrics (SM_CXDLGFRAME)); iyBorders = 2 * (GetSystemMetrics (SM_CYBORDER) + GetSystemMetrics (SM_CYDLGFRAME)) + @@ -122,9 +123,9 @@ hwnd = CreateWindow (szProgName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 512 + 2 * MARGIN + ixBorders, 384 + 2 * MARGIN + iyBorders, -// CW_USEDEFAULT, CW_USEDEFAULT, +/* CW_USEDEFAULT, CW_USEDEFAULT, */ NULL, NULL, hInstance, NULL); ShowWindow (hwnd, iCmdShow); UpdateWindow (hwnd); @@ -179,31 +180,31 @@ PngFileInitialize (hwnd); strcpy (szImgPathName, ""); - // in case we process file given on command-line + /* 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 + /* read the other png-files in the directory for later */ + /* next/previous commands */ BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount, &iPngFileIndex); - // load the image from file + /* load the image from file */ if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor)) return 0; - // invalidate the client area for later update + /* invalidate the client area for later update */ InvalidateRect (hwnd, NULL, TRUE); - // display the PNG into the DIBitmap + /* display the PNG into the DIBitmap */ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); } @@ -213,13 +214,13 @@ case WM_SIZE: cxWinSize = LOWORD (lParam); cyWinSize = HIWORD (lParam); - // invalidate the client area for later update + /* invalidate the client area for later update */ InvalidateRect (hwnd, NULL, TRUE); - // display the PNG into the DIBitmap + /* display the PNG into the DIBitmap */ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); @@ -241,44 +242,44 @@ switch (LOWORD (wParam)) { case IDM_FILE_OPEN: - // show the File Open dialog box + /* 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 + /* read the other png-files in the directory for later */ + /* next/previous commands */ BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount, &iPngFileIndex); - // load the image from file + /* load the image from file */ if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor)) return 0; - // invalidate the client area for later update + /* invalidate the client area for later update */ InvalidateRect (hwnd, NULL, TRUE); - // display the PNG into the DIBitmap + /* 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 + /* show the File Save dialog box */ if (!PngFileSaveDlg (hwnd, szImgPathName, szTitleName)) return 0; - // save the PNG to a disk file + /* save the PNG to a disk file */ SetCursor (LoadCursor (NULL, IDC_WAIT)); ShowCursor (TRUE); @@ -294,27 +295,27 @@ return 0; case IDM_FILE_NEXT: - // read next entry in the directory + /* read next entry in the directory */ if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex, NULL, szImgPathName)) { if (strcmp (szImgPathName, "") == 0) return 0; - // load the image from file + /* load the image from file */ if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor)) return 0; - // invalidate the client area for later update + /* invalidate the client area for later update */ InvalidateRect (hwnd, NULL, TRUE); - // display the PNG into the DIBitmap + /* display the PNG into the DIBitmap */ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); } @@ -322,28 +323,28 @@ return 0; case IDM_FILE_PREVIOUS: - // read previous entry in the directory + /* read previous entry in the directory */ if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex, szImgPathName, NULL)) { if (strcmp (szImgPathName, "") == 0) return 0; - // load the image from file + /* load the image from file */ if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor)) return 0; - // invalidate the client area for later update + /* invalidate the client area for later update */ InvalidateRect (hwnd, NULL, TRUE); - // display the PNG into the DIBitmap + /* display the PNG into the DIBitmap */ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); } @@ -351,27 +352,27 @@ return 0; case IDM_FILE_EXIT: - // more cleanup needed... + /* more cleanup needed... */ - // free image buffer + /* free image buffer */ if (pDib != NULL) { free (pDib); pDib = NULL; } - // free file-list + /* free file-list */ if (pPngFileList != NULL) { free (pPngFileList); pPngFileList = NULL; } - // let's go ... + /* let's go ... */ exit (0); return 0; @@ -382,13 +383,13 @@ CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_CHECKED); else CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_UNCHECKED); - // invalidate the client area for later update + /* invalidate the client area for later update */ InvalidateRect (hwnd, NULL, TRUE); - // display the PNG into the DIBitmap + /* display the PNG into the DIBitmap */ DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize, pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched); @@ -397,9 +398,9 @@ case IDM_HELP_ABOUT: DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc) ; return 0; - } // end switch + } /* end switch */ break; case WM_PAINT: @@ -449,32 +450,32 @@ } return FALSE ; } -//--------------- -// CenterAbout -//--------------- - +/*--------------- + * 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 + /* 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 + /* 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' + /* Get the limits of the 'workarea' */ bResult = SystemParametersInfo( - SPI_GETWORKAREA, // system parameter to query or set + SPI_GETWORKAREA, /* system parameter to query or set */ sizeof(RECT), &rWorkArea, 0); if (!bResult) { @@ -482,33 +483,33 @@ rWorkArea.right = GetSystemMetrics(SM_CXSCREEN); rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN); } - // Calculate new X position, then adjust for workarea + /* 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 + /* 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 + /* Set it, and return */ return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } -//---------------- -// BuildPngList -//---------------- - +/*---------------- + * BuildPngList + *---------------- + */ BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount, int *pFileIndex) { static TCHAR szImgPathName [MAX_PATH]; @@ -522,26 +523,26 @@ BOOL bOk; int i, ii; int j, jj; - // free previous file-list + /* free previous file-list */ if (*ppFileList != NULL) { free (*ppFileList); *ppFileList = NULL; } - // extract foldername, filename and search-name + /* 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 + /* first cycle: count number of files in directory for memory allocation */ *pFileCount = 0; hFind = FindFirstFile(szImgFindName, &finddata); @@ -553,13 +554,13 @@ bOk = FindNextFile(hFind, &finddata); } FindClose(hFind); - // allocation memory for file-list + /* allocation memory for file-list */ *ppFileList = (TCHAR *) malloc (*pFileCount * MAX_PATH); - // second cycle: read directory and store filenames in file-list + /* second cycle: read directory and store filenames in file-list */ hFind = FindFirstFile(szImgFindName, &finddata); bOk = (hFind != (HANDLE) -1); @@ -579,9 +580,9 @@ bOk = FindNextFile(hFind, &finddata); } FindClose(hFind); - // finally we must sort the file-list + /* finally we must sort the file-list */ for (i = 0; i < *pFileCount - 1; i++) { ii = i * MAX_PATH; @@ -593,9 +594,9 @@ strcpy (szTmp, *ppFileList + jj); strcpy (*ppFileList + jj, *ppFileList + ii); strcpy (*ppFileList + ii, szTmp); - // check if this was the current image that we moved + /* check if this was the current image that we moved */ if (*pFileIndex == i) *pFileIndex = j; else @@ -607,19 +608,20 @@ return TRUE; } -//---------------- -// SearchPngList -//---------------- +/*---------------- + * SearchPngList + *---------------- + */ BOOL SearchPngList ( TCHAR *pFileList, int FileCount, int *pFileIndex, PTSTR pstrPrevName, PTSTR pstrNextName) { if (FileCount > 0) { - // get previous entry + /* get previous entry */ if (pstrPrevName != NULL) { if (*pFileIndex > 0) @@ -629,9 +631,9 @@ strcpy (pstrPrevName, pFileList + (*pFileIndex * MAX_PATH)); } - // get next entry + /* get next entry */ if (pstrNextName != NULL) { if (*pFileIndex < FileCount - 1) @@ -649,27 +651,28 @@ return FALSE; } } -//----------------- -// LoadImageFile -//----------------- +/*----------------- + * 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 there's an existing PNG, free the memory */ if (*ppbImage) { free (*ppbImage); *ppbImage = NULL; } - // Load the entire PNG into memory + /* Load the entire PNG into memory */ SetCursor (LoadCursor (NULL, IDC_WAIT)); ShowCursor (TRUE); @@ -693,27 +696,27 @@ return TRUE; } -//---------------- -// DisplayImage -//---------------- - +/*---------------- + * 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; + /* 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 + /* allocate memory for the Device Independant bitmap */ wDIRowBytes = (WORD) ((3 * cxWinSize + 3L) >> 2) << 2; if (pDib) @@ -732,9 +735,9 @@ } *ppDib = pDib; memset (pDib, 0, sizeof(BITMAPINFOHEADER)); - // initialize the dib-structure + /* initialize the dib-structure */ pbmih = (BITMAPINFOHEADER *) pDib; pbmih->biSize = sizeof(BITMAPINFOHEADER); pbmih->biWidth = cxWinSize; @@ -744,13 +747,13 @@ pbmih->biCompression = 0; pDiData = pDib + sizeof(BITMAPINFOHEADER); *ppDiData = pDiData; - // first fill bitmap with gray and image border + /* first fill bitmap with gray and image border */ InitBitmap (pDiData, cxWinSize, cyWinSize); - // then fill bitmap with image + /* then fill bitmap with image */ if (pbImage) { FillBitmap ( @@ -761,32 +764,32 @@ return TRUE; } -//-------------- -// InitBitmap -//-------------- - +/*-------------- + * InitBitmap + *-------------- + */ BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize) { BYTE *dst; int x, y, col; - // initialize the background with gray + /* initialize the background with gray */ dst = pDiData; for (y = 0; y < cyWinSize; y++) { col = 0; for (x = 0; x < cxWinSize; x++) { - // fill with GRAY + /* fill with GRAY */ *dst++ = 127; *dst++ = 127; *dst++ = 127; col += 3; } - // rows start on 4 byte boundaries + /* rows start on 4 byte boundaries */ while ((col % 4) != 0) { dst++; col++; @@ -795,12 +798,12 @@ return TRUE; } -//-------------- -// FillBitmap -//-------------- - +/*-------------- + * FillBitmap + *-------------- + */ BOOL FillBitmap ( BYTE *pDiData, int cxWinSize, int cyWinSize, BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels, BOOL bStretched) @@ -823,13 +826,14 @@ { cxNewSize = cxWinSize - 2 * MARGIN; cyNewSize = cyWinSize - 2 * MARGIN; - // stretch the image to it's window determined size + /* stretch the image to it's window determined size */ - // the following two are the same, but the first has side-effects - // because of rounding -// if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize)) + /* 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; @@ -866,14 +870,14 @@ } } } - // calculate row-bytes + /* calculate row-bytes */ wImgRowBytes = cImgChannels * cxNewSize; wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2; - // copy image to screen + /* copy image to screen */ for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++) { if (yWin >= cyWinSize - cyImgPos) @@ -897,9 +901,9 @@ } } } - // free memory + /* free memory */ if (pStretchedImage != NULL) { free (pStretchedImage); @@ -907,30 +911,30 @@ } } - // process the image not-stretched + /* process the image not-stretched */ else { - // calculate the central position + /* calculate the central position */ cxImgPos = (cxWinSize - cxImgSize) / 2; cyImgPos = (cyWinSize - cyImgSize) / 2; - // check for image larger than window + /* check for image larger than window */ if (cxImgPos < MARGIN) cxImgPos = MARGIN; if (cyImgPos < MARGIN) cyImgPos = MARGIN; - // calculate both row-bytes + /* calculate both row-bytes */ wImgRowBytes = cImgChannels * cxImgSize; wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2; - // copy image to screen + /* copy image to screen */ for (yImg = 0, yWin = cyImgPos; yImg < cyImgSize; yImg++, yWin++) { if (yWin >= cyWinSize - MARGIN) @@ -958,7 +962,8 @@ return TRUE; } -//----------------- -// end of source -//----------------- +/*----------------- + * end of source + *----------------- + */ diff -ru4NwbB libpng-1.5.4/png.c libpng-1.5.5beta07/png.c --- libpng-1.5.4/png.c 2011-07-07 06:24:48.277563190 -0500 +++ libpng-1.5.5beta07/png.c 2011-09-08 12:21:33.549548312 -0500 @@ -1,8 +1,8 @@ /* png.c - location for general purpose libpng functions * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -42,9 +42,9 @@ * already read the first few bytes of a file to determine the file type * can simply check the remaining bytes for extra assurance. Returns * an integer less than, equal to, or greater than zero if sig is found, * respectively, to be less than, to match, or be greater than the correct - * PNG signature (this is the same behaviour as strcmp, memcmp, etc). + * PNG signature (this is the same behavior as strcmp, memcmp, etc). */ int PNGAPI png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check) { @@ -541,10 +541,10 @@ # ifdef PNG_STDIO_SUPPORTED /* Initialize the default input/output functions for the PNG file. If you * use your own read or write routines, you can call either png_set_read_fn() * or png_set_write_fn() instead of png_init_io(). If you have defined - * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't - * necessarily available. + * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a + * function of your own because "FILE *" isn't necessarily available. */ void PNGAPI png_init_io(png_structp png_ptr, png_FILE_p fp) { @@ -712,20 +712,11 @@ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -# ifdef PNG_SIZE_T -/* Added at libpng version 1.2.6 */ - PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); -png_size_t PNGAPI -png_convert_size(size_t size) -{ - if (size > (png_size_t)-1) - PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ - - return ((png_size_t)size); -} -# endif /* PNG_SIZE_T */ +/* png_convert_size: a PNGAPI but no longer in png.h, so deleted + * at libpng 1.5.5! + */ /* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ # ifdef PNG_CHECK_cHRM_SUPPORTED @@ -797,8 +788,328 @@ return ret; } # endif /* PNG_CHECK_cHRM_SUPPORTED */ +#ifdef PNG_cHRM_SUPPORTED +/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for + * cHRM, as opposed to using chromaticities. These internal APIs return + * non-zero on a parameter error. The X, Y and Z values are required to be + * positive and less than 1.0. + */ +int png_xy_from_XYZ(png_xy *xy, png_XYZ XYZ) +{ + png_int_32 d, dwhite, whiteX, whiteY; + + d = XYZ.redX + XYZ.redY + XYZ.redZ; + if (!png_muldiv(&xy->redx, XYZ.redX, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->redy, XYZ.redY, PNG_FP_1, d)) return 1; + dwhite = d; + whiteX = XYZ.redX; + whiteY = XYZ.redY; + + d = XYZ.greenX + XYZ.greenY + XYZ.greenZ; + if (!png_muldiv(&xy->greenx, XYZ.greenX, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->greeny, XYZ.greenY, PNG_FP_1, d)) return 1; + dwhite += d; + whiteX += XYZ.greenX; + whiteY += XYZ.greenY; + + d = XYZ.blueX + XYZ.blueY + XYZ.blueZ; + if (!png_muldiv(&xy->bluex, XYZ.blueX, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->bluey, XYZ.blueY, PNG_FP_1, d)) return 1; + dwhite += d; + whiteX += XYZ.blueX; + whiteY += XYZ.blueY; + + /* The reference white is simply the same of the end-point (X,Y,Z) vectors, + * thus: + */ + if (!png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite)) return 1; + if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) return 1; + + return 0; +} + +int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy) +{ + png_fixed_point red_inverse, green_inverse, blue_scale; + png_fixed_point left, right, denominator; + + /* Check xy and, implicitly, z. Note that wide gamut color spaces typically + * have end points with 0 tristimulus values (these are impossible end + * points, but they are used to cover the possible colors.) + */ + if (xy.redx < 0 || xy.redx > PNG_FP_1) return 1; + if (xy.redy < 0 || xy.redy > PNG_FP_1-xy.redx) return 1; + if (xy.greenx < 0 || xy.greenx > PNG_FP_1) return 1; + if (xy.greeny < 0 || xy.greeny > PNG_FP_1-xy.greenx) return 1; + if (xy.bluex < 0 || xy.bluex > PNG_FP_1) return 1; + if (xy.bluey < 0 || xy.bluey > PNG_FP_1-xy.bluex) return 1; + if (xy.whitex < 0 || xy.whitex > PNG_FP_1) return 1; + if (xy.whitey < 0 || xy.whitey > PNG_FP_1-xy.whitex) return 1; + + /* The reverse calculation is more difficult because the original tristimulus + * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 + * derived values were recorded in the cHRM chunk; + * (red,green,blue,white)x(x,y). This loses one degree of freedom and + * therefore an arbitrary ninth value has to be introduced to undo the + * original transformations. + * + * Think of the original end-points as points in (X,Y,Z) space. The + * chromaticity values (c) have the property: + * + * C + * c = --------- + * X + Y + Z + * + * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the + * three chromaticity values (x,y,z) for each end-point obey the + * relationship: + * + * x + y + z = 1 + * + * This describes the plane in (X,Y,Z) space that intersects each axis at the + * value 1.0; call this the chromaticity plane. Thus the chromaticity + * calculation has scaled each end-point so that it is on the x+y+z=1 plane + * and chromaticity is the intersection of the vector from the origin to the + * (X,Y,Z) value with the chromaticity plane. + * + * To fully invert the chromaticity calculation we would need the three + * end-point scale factors, (red-scale, green-scale, blue-scale), but these + * were not recorded. Instead we calculated the reference white (X,Y,Z) and + * recorded the chromaticity of this. The reference white (X,Y,Z) would have + * given all three of the scale factors since: + * + * color-C = color-c * color-scale + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * But cHRM records only white-x and white-y, so we have lost the white scale + * factor: + * + * white-C = white-c*white-scale + * + * To handle this the inverse transformation makes an arbitrary assumption + * about white-scale: + * + * Assume: white-Y = 1.0 + * Hence: white-scale = 1/white-y + * Or: red-Y + green-Y + blue-Y = 1.0 + * + * Notice the last statement of the assumption gives an equation in three of + * the nine values we want to calculate. 8 more equations come from the + * above routine as summarised at the top above (the chromaticity + * calculation): + * + * Given: color-x = color-X / (color-X + color-Y + color-Z) + * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0 + * + * This is 9 simultaneous equations in the 9 variables "color-C" and can be + * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix + * determinants, however this is not as bad as it seems because only 28 of + * the total of 90 terms in the various matrices are non-zero. Nevertheless + * Cramer's rule is notoriously numerically unstable because the determinant + * calculation involves the difference of large, but similar, numbers. It is + * difficult to be sure that the calculation is stable for real world values + * and it is certain that it becomes unstable where the end points are close + * together. + * + * So this code uses the perhaps slighly less optimal but more understandable + * and totally obvious approach of calculating color-scale. + * + * This algorithm depends on the precision in white-scale and that is + * (1/white-y), so we can immediately see that as white-y approaches 0 the + * accuracy inherent in the cHRM chunk drops off substantially. + * + * libpng arithmetic: a simple invertion of the above equations + * ------------------------------------------------------------ + * + * white_scale = 1/white-y + * white-X = white-x * white-scale + * white-Y = 1.0 + * white-Z = (1 - white-x - white-y) * white_scale + * + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * This gives us three equations in (red-scale,green-scale,blue-scale) where + * all the coefficients are now known: + * + * red-x*red-scale + green-x*green-scale + blue-x*blue-scale + * = white-x/white-y + * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1 + * red-z*red-scale + green-z*green-scale + blue-z*blue-scale + * = (1 - white-x - white-y)/white-y + * + * In the last equation color-z is (1 - color-x - color-y) so we can add all + * three equations together to get an alternative third: + * + * red-scale + green-scale + blue-scale = 1/white-y = white-scale + * + * So now we have a Cramer's rule solution where the determinants are just + * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve + * multiplication of three coefficients so we can't guarantee to avoid + * overflow in the libpng fixed point representation. Using Cramer's rule in + * floating point is probably a good choice here, but it's not an option for + * fixed point. Instead proceed to simplify the first two equations by + * eliminating what is likely to be the largest value, blue-scale: + * + * blue-scale = white-scale - red-scale - green-scale + * + * Hence: + * + * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale = + * (white-x - blue-x)*white-scale + * + * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale = + * 1 - blue-y*white-scale + * + * And now we can trivially solve for (red-scale,green-scale): + * + * green-scale = + * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale + * ----------------------------------------------------------- + * green-x - blue-x + * + * red-scale = + * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale + * --------------------------------------------------------- + * red-y - blue-y + * + * Hence: + * + * red-scale = + * ( (green-x - blue-x) * (white-y - blue-y) - + * (green-y - blue-y) * (white-x - blue-x) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * green-scale = + * ( (red-y - blue-y) * (white-x - blue-x) - + * (red-x - blue-x) * (white-y - blue-y) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * Accuracy: + * The input values have 5 decimal digits of accuracy. The values are all in + * the range 0 < value < 1, so simple products are in the same range but may + * need up to 10 decimal digits to preserve the original precision and avoid + * underflow. Because we are using a 32-bit signed representation we cannot + * match this; the best is a little over 9 decimal digits, less than 10. + * + * The approach used here is to preserve the maximum precision within the + * signed representation. Because the red-scale calculation above uses the + * difference between two products of values that must be in the range -1..+1 + * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The + * factor is irrelevant in the calculation because it is applied to both + * numerator and denominator. + * + * Note that the values of the differences of the products of the + * chromaticities in the above equations tend to be small, for example for + * the sRGB chromaticities they are: + * + * red numerator: -0.04751 + * green numerator: -0.08788 + * denominator: -0.2241 (without white-y multiplication) + * + * The resultant Y coefficients from the chromaticities of some widely used + * color space definitions are (to 15 decimal places): + * + * sRGB + * 0.212639005871510 0.715168678767756 0.072192315360734 + * Kodak ProPhoto + * 0.288071128229293 0.711843217810102 0.000085653960605 + * Adobe RGB + * 0.297344975250536 0.627363566255466 0.075291458493998 + * Adobe Wide Gamut RGB + * 0.258728243040113 0.724682314948566 0.016589442011321 + */ + /* By the argument, above overflow should be impossible here. The return + * value of 2 indicates an internal error to the caller. + */ + if (!png_muldiv(&left, xy.greenx-xy.bluex, xy.redy - xy.bluey, 7)) return 2; + if (!png_muldiv(&right, xy.greeny-xy.bluey, xy.redx - xy.bluex, 7)) return 2; + denominator = left - right; + + /* Now find the red numerator. */ + if (!png_muldiv(&left, xy.greenx-xy.bluex, xy.whitey-xy.bluey, 7)) return 2; + if (!png_muldiv(&right, xy.greeny-xy.bluey, xy.whitex-xy.bluex, 7)) return 2; + + /* Overflow is possible here and it indicates an extreme set of PNG cHRM + * chunk values. This calculation actually returns the reciprocal of the + * scale value because this allows us to delay the multiplication of white-y + * into the denominator, which tends to produce a small number. + */ + if (!png_muldiv(&red_inverse, xy.whitey, denominator, left-right) || + red_inverse <= xy.whitey /* r+g+b scales = white scale */) + return 1; + + /* Similarly for green_inverse: */ + if (!png_muldiv(&left, xy.redy-xy.bluey, xy.whitex-xy.bluex, 7)) return 2; + if (!png_muldiv(&right, xy.redx-xy.bluex, xy.whitey-xy.bluey, 7)) return 2; + if (!png_muldiv(&green_inverse, xy.whitey, denominator, left-right) || + green_inverse <= xy.whitey) + return 1; + + /* And the blue scale, the checks above guarantee this can't overflow but it + * can still produce 0 for extreme cHRM values. + */ + blue_scale = png_reciprocal(xy.whitey) - png_reciprocal(red_inverse) - + png_reciprocal(green_inverse); + if (blue_scale <= 0) return 1; + + + /* And fill in the png_XYZ: */ + if (!png_muldiv(&XYZ->redX, xy.redx, PNG_FP_1, red_inverse)) return 1; + if (!png_muldiv(&XYZ->redY, xy.redy, PNG_FP_1, red_inverse)) return 1; + if (!png_muldiv(&XYZ->redZ, PNG_FP_1 - xy.redx - xy.redy, PNG_FP_1, + red_inverse)) + return 1; + + if (!png_muldiv(&XYZ->greenX, xy.greenx, PNG_FP_1, green_inverse)) return 1; + if (!png_muldiv(&XYZ->greenY, xy.greeny, PNG_FP_1, green_inverse)) return 1; + if (!png_muldiv(&XYZ->greenZ, PNG_FP_1 - xy.greenx - xy.greeny, PNG_FP_1, + green_inverse)) + return 1; + + if (!png_muldiv(&XYZ->blueX, xy.bluex, blue_scale, PNG_FP_1)) return 1; + if (!png_muldiv(&XYZ->blueY, xy.bluey, blue_scale, PNG_FP_1)) return 1; + if (!png_muldiv(&XYZ->blueZ, PNG_FP_1 - xy.bluex - xy.bluey, blue_scale, + PNG_FP_1)) + return 1; + + return 0; /*success*/ +} + +int png_XYZ_from_xy_checked(png_structp png_ptr, png_XYZ *XYZ, png_xy xy) +{ + switch (png_XYZ_from_xy(XYZ, xy)) + { + case 0: /* success */ + return 1; + + case 1: + /* The chunk may be technically valid, but we got png_fixed_point + * overflow while trying to get XYZ values out of it. This is + * entirely benign - the cHRM chunk is pretty extreme. + */ + png_warning(png_ptr, + "extreme cHRM chunk cannot be converted to tristimulus values"); + break; + + default: + /* libpng is broken; this should be a warning but if it happens we + * want error reports so for the moment it is an error. + */ + png_error(png_ptr, "internal error in png_XYZ_from_xy"); + break; + } + + /* ERROR RETURN */ + return 0; +} +#endif + void /* PRIVATE */ png_check_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, diff -ru4NwbB libpng-1.5.4/png.h libpng-1.5.5beta07/png.h --- libpng-1.5.4/png.h 2011-07-07 06:24:48.226988784 -0500 +++ libpng-1.5.5beta07/png.h 2011-09-08 12:21:33.498911625 -0500 @@ -156,8 +156,9 @@ * 1.5.3 [omitted] * 1.5.4beta01-08 15 10504 15.so.15.4[.0] * 1.5.4rc01 15 10504 15.so.15.4[.0] * 1.5.4 15 10504 15.so.15.4[.0] + * 1.5.5beta01-07 15 10505 15.so.15.5[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be * used for changes in backward compatibility, as it is intended. The @@ -2046,8 +2047,12 @@ PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structp png_ptr, png_const_infop info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, double *green_x, double *green_y, double *blue_x, double *blue_y)); +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_structp png_ptr, + png_const_infop info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)); #ifdef PNG_FIXED_POINT_SUPPORTED /* Otherwise not implemented */ PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, (png_const_structp png_ptr, png_const_infop info_ptr, png_fixed_point *int_white_x, @@ -2055,21 +2060,38 @@ png_fixed_point *int_red_y, png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)); #endif +PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, + (png_structp png_ptr, png_const_infop info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z)); #endif #ifdef PNG_cHRM_SUPPORTED PNG_FP_EXPORT(135, void, png_set_cHRM, (png_structp png_ptr, png_infop info_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, double blue_x, double blue_y)); +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_structp png_ptr, + png_infop info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)); PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_structp png_ptr, png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, png_fixed_point int_blue_y)); +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z)); #endif #ifdef PNG_gAMA_SUPPORTED PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, @@ -2281,9 +2303,9 @@ /* Provide a list of chunks and how they are to be handled, if the built-in handling or default unknown chunk handling is not desired. Any chunks not listed will be handled in the default manner. The IHDR and IEND chunks must not be listed. - keep = 0: follow default behaviour + keep = 0: follow default behavior = 1: do not keep = 2: keep only if safe-to-copy = 3: keep even if unsafe-to-copy */ @@ -2575,9 +2597,9 @@ * one to use is one more than this.) Maintainer, remember to add an entry to * scripts/symbols.def as well. */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(229); + PNG_EXPORT_LAST_ORDINAL(233); #endif #ifdef __cplusplus } diff -ru4NwbB libpng-1.5.4/pngconf.h libpng-1.5.5beta07/pngconf.h --- libpng-1.5.4/pngconf.h 2011-07-07 06:24:48.233989899 -0500 +++ libpng-1.5.5beta07/pngconf.h 2011-09-08 12:21:33.505566540 -0500 @@ -163,9 +163,11 @@ * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to * 'type', compiler specific. * * PNG_DLL_EXPORT Set to the magic to use during a libpng build to - * make a symbol exported from the DLL. + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. * * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come * from a DLL - used to define PNG_IMPEXP when * PNG_USE_DLL is set. @@ -257,28 +259,17 @@ #ifndef PNGAPI # define PNGAPI PNGCAPI #endif -/* The default for PNG_IMPEXP depends on whether the library is - * being built or used. +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. */ #ifndef PNG_IMPEXP -# ifdef PNGLIB_BUILD - /* Building the library */ -# if (defined(DLL_EXPORT)/*from libtool*/ ||\ - defined(_WINDLL) || defined(_DLL) || defined(__DLL__) ||\ - defined(_USRDLL) ||\ - defined(PNG_BUILD_DLL)) && defined(PNG_DLL_EXPORT) - /* Building a DLL. */ -# define PNG_IMPEXP PNG_DLL_EXPORT -# endif /* DLL */ -# else - /* Using the library */ # if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) /* This forces use of a DLL, disallowing static linking */ # define PNG_IMPEXP PNG_DLL_IMPORT # endif -# endif # ifndef PNG_IMPEXP # define PNG_IMPEXP # endif @@ -355,14 +346,8 @@ # endif # ifndef PNG_ALLOCATED # define PNG_ALLOCATED __attribute__((__malloc__)) # endif - - /* This specifically protects structure members that should only be - * accessed from within the library, therefore should be empty during - * a library build. - */ -# ifndef PNGLIB_BUILD # ifndef PNG_DEPRECATED # define PNG_DEPRECATED __attribute__((__deprecated__)) # endif # ifndef PNG_PRIVATE @@ -373,9 +358,8 @@ # define PNG_PRIVATE \ __attribute__((__deprecated__)) # endif # endif -# endif /* PNGLIB_BUILD */ # endif /* __GNUC__ */ # if defined(_MSC_VER) && (_MSC_VER >= 1300) # ifndef PNG_USE_RESULT @@ -384,25 +368,18 @@ # ifndef PNG_NORETURN # define PNG_NORETURN __declspec(noreturn) # endif # ifndef PNG_ALLOCATED -# if (_MSC_VER >= 1400) +# if defined(_MSC_VER) && (_MSC_VER >= 1300) # define PNG_ALLOCATED __declspec(restrict) # endif # endif - - /* This specifically protects structure members that should only be - * accessed from within the library, therefore should be empty during - * a library build. - */ -# ifndef PNGLIB_BUILD # ifndef PNG_DEPRECATED # define PNG_DEPRECATED __declspec(deprecated) # endif # ifndef PNG_PRIVATE # define PNG_PRIVATE __declspec(deprecated) # endif -# endif /* PNGLIB_BUILD */ # endif /* _MSC_VER */ #endif /* PNG_PEDANTIC_WARNINGS */ #ifndef PNG_DEPRECATED diff -ru4NwbB libpng-1.5.4/pngget.c libpng-1.5.5beta07/pngget.c --- libpng-1.5.4/pngget.c 2011-07-07 06:24:48.291782588 -0500 +++ libpng-1.5.5beta07/pngget.c 2011-09-08 12:21:33.563997511 -0500 @@ -1,8 +1,8 @@ /* pngget.c - retrieval of values from info struct * - * Last changed in libpng 1.5.1 [February 3, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -458,8 +458,67 @@ } #endif #ifdef PNG_cHRM_SUPPORTED +/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the + * same time to correct the rgb grayscale coefficient defaults obtained from the + * cHRM chunk in 1.5.4 + */ +png_uint_32 PNGFAPI +png_get_cHRM_XYZ_fixed(png_structp png_ptr, png_const_infop info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_xy xy; + png_XYZ XYZ; + + png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); + + xy.whitex = info_ptr->x_white; + xy.whitey = info_ptr->y_white; + xy.redx = info_ptr->x_red; + xy.redy = info_ptr->y_red; + xy.greenx = info_ptr->x_green; + xy.greeny = info_ptr->y_green; + xy.bluex = info_ptr->x_blue; + xy.bluey = info_ptr->y_blue; + + /* The *_checked function handles error reporting, so just return 0 if + * there is a failure here. + */ + if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy)) + { + if (int_red_X != NULL) + *int_red_X = XYZ.redX; + if (int_red_Y != NULL) + *int_red_Y = XYZ.redY; + if (int_red_Z != NULL) + *int_red_Z = XYZ.redZ; + if (int_green_X != NULL) + *int_green_X = XYZ.greenX; + if (int_green_Y != NULL) + *int_green_Y = XYZ.greenY; + if (int_green_Z != NULL) + *int_green_Z = XYZ.greenZ; + if (int_blue_X != NULL) + *int_blue_X = XYZ.blueX; + if (int_blue_Y != NULL) + *int_blue_Y = XYZ.blueY; + if (int_blue_Z != NULL) + *int_blue_Z = XYZ.blueZ; + + return (PNG_INFO_cHRM); + } + } + + return (0); +} + # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI png_get_cHRM(png_const_structp png_ptr, png_const_infop info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, @@ -489,8 +548,44 @@ } return (0); } + +png_uint_32 PNGAPI +png_get_cHRM_XYZ(png_structp png_ptr, png_const_infop info_ptr, + double *red_X, double *red_Y, double *red_Z, double *green_X, + double *green_Y, double *green_Z, double *blue_X, double *blue_Y, + double *blue_Z) +{ + png_XYZ XYZ; + + if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, + &XYZ.redX, &XYZ.redY, &XYZ.redZ, &XYZ.greenX, &XYZ.greenY, &XYZ.greenZ, + &XYZ.blueX, &XYZ.blueY, &XYZ.blueZ) & PNG_INFO_cHRM) + { + if (red_X != NULL) + *red_X = png_float(png_ptr, XYZ.redX, "cHRM red X"); + if (red_Y != NULL) + *red_Y = png_float(png_ptr, XYZ.redY, "cHRM red Y"); + if (red_Z != NULL) + *red_Z = png_float(png_ptr, XYZ.redZ, "cHRM red Z"); + if (green_X != NULL) + *green_X = png_float(png_ptr, XYZ.greenX, "cHRM green X"); + if (green_Y != NULL) + *green_Y = png_float(png_ptr, XYZ.greenY, "cHRM green Y"); + if (green_Z != NULL) + *green_Z = png_float(png_ptr, XYZ.greenZ, "cHRM green Z"); + if (blue_X != NULL) + *blue_X = png_float(png_ptr, XYZ.blueX, "cHRM blue X"); + if (blue_Y != NULL) + *blue_Y = png_float(png_ptr, XYZ.blueY, "cHRM blue Y"); + if (blue_Z != NULL) + *blue_Z = png_float(png_ptr, XYZ.blueZ, "cHRM blue Z"); + return (PNG_INFO_cHRM); + } + + return (0); +} # endif # ifdef PNG_FIXED_POINT_SUPPORTED png_uint_32 PNGAPI diff -ru4NwbB libpng-1.5.4/pngpriv.h libpng-1.5.5beta07/pngpriv.h --- libpng-1.5.4/pngpriv.h 2011-07-07 06:24:48.242719187 -0500 +++ libpng-1.5.5beta07/pngpriv.h 2011-09-08 12:21:33.514457247 -0500 @@ -5,9 +5,9 @@ * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h @@ -43,9 +43,10 @@ * error handler when all else fails. */ #include -#define PNGLIB_BUILD +#define PNGLIB_BUILD /*libpng is being built, not used*/ + #ifdef PNG_USER_CONFIG # include "pngusr.h" /* These should have been defined in pngusr.h */ # ifndef PNG_USER_PRIVATEBUILD @@ -54,12 +55,82 @@ # ifndef PNG_USER_DLLFNAME_POSTFIX # define PNG_USER_DLLFNAME_POSTFIX "Cb" # endif #endif + +/* Is this a build of a DLL where compilation of the object modules requires + * different preprocessor settings to those required for a simple library? If + * so PNG_BUILD_DLL must be set. + * + * If libpng is used inside a DLL but that DLL does not export the libpng APIs + * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a + * static library of libpng then link the DLL against that. + */ +#ifndef PNG_BUILD_DLL +# ifdef DLL_EXPORT + /* This is set by libtool when files are compiled for a DLL; libtool + * always compiles twice, even on systems where it isn't necessary. Set + * PNG_BUILD_DLL in case it is necessary: + */ +# define PNG_BUILD_DLL +# else +# ifdef _WINDLL + /* This is set by the Microsoft Visual Studio IDE in projects that + * build a DLL. It can't easily be removed from those projects (it + * isn't visible in the Visual Studio UI) so it is a fairly reliable + * indication that PNG_IMPEXP needs to be set to the DLL export + * attributes. + */ +# define PNG_BUILD_DLL +# else +# ifdef __DLL__ + /* This is set by the Borland C system when compiling for a DLL + * (as above.) + */ +# define PNG_BUILD_DLL +# else + /* Add additional compiler cases here. */ +# endif +# endif +# endif +#endif /* Setting PNG_BUILD_DLL if required */ + +/* See pngconf.h for more details: the builder of the library may set this on + * the command line to the right thing for the specific compilation system or it + * may be automagically set above (at present we know of no system where it does + * need to be set on the command line.) + * + * PNG_IMPEXP must be set here when building the library to prevent pngconf.h + * setting it to the "import" setting for a DLL build. + */ +#ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP PNG_DLL_EXPORT +# else + /* Not building a DLL, or the DLL doesn't require specific export + * definitions. + */ +# define PNG_IMPEXP +# endif +#endif + +/* No warnings for private or deprecated functions in the build: */ +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE +#endif + #include "png.h" #include "pnginfo.h" #include "pngstruct.h" +/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ +#ifndef PNG_DLL_EXPORT +# define PNG_DLL_EXPORT +#endif + /* This is used for 16 bit gamma tables - only the top level pointers are const, * this could be changed: */ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; @@ -1077,8 +1148,37 @@ PNG_EXTERN void png_64bit_product PNGARG((long v1, long v2, unsigned long *hi_product, unsigned long *lo_product)); #endif +#ifdef PNG_cHRM_SUPPORTED +/* Added at libpng version 1.5.5 */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +typedef struct png_XYZ +{ + png_fixed_point redX, redY, redZ; + png_fixed_point greenX, greenY, greenZ; + png_fixed_point blueX, blueY, blueZ; +} png_XYZ; + +/* The conversion APIs return 0 on success, non-zero on a parameter error. They + * allow conversion between the above representations of a color encoding. When + * converting from XYZ end points to chromaticities the absolute magnitude of + * the end points is lost, when converting back the sum of the Y values of the + * three end points will be 1.0 + */ +PNG_EXTERN int png_xy_from_XYZ PNGARG((png_xy *xy, png_XYZ XYZ)); +PNG_EXTERN int png_XYZ_from_xy PNGARG((png_XYZ *XYZ, png_xy xy)); +PNG_EXTERN int png_XYZ_from_xy_checked PNGARG((png_structp png_ptr, + png_XYZ *XYZ, png_xy xy)); +#endif + /* Added at libpng version 1.4.0 */ PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, diff -ru4NwbB libpng-1.5.4/pngrtran.c libpng-1.5.5beta07/pngrtran.c --- libpng-1.5.4/pngrtran.c 2011-07-07 06:24:48.338363499 -0500 +++ libpng-1.5.5beta07/pngrtran.c 2011-09-08 12:21:33.610018674 -0500 @@ -1,8 +1,8 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -967,34 +967,39 @@ if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) { png_uint_16 red_int, green_int; + /* NOTE: this calculation does not round, but this behavior is retained + * for consistency, the inaccuracy is very small. The code here always + * overwrites the coefficients, regardless of whether they have been + * defaulted or set already. + */ red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); png_ptr->rgb_to_gray_red_coeff = red_int; png_ptr->rgb_to_gray_green_coeff = green_int; - png_ptr->rgb_to_gray_blue_coeff = - (png_uint_16)(32768 - red_int - green_int); + png_ptr->rgb_to_gray_coefficients_set = 1; } else { if (red >= 0 && green >= 0) png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); - /* Use the defaults, from the cHRM chunk if set, else the built in Rec - * 709 values (which correspond to sRGB, so we don't have to worry - * about the sRGB chunk!) + /* Use the defaults, from the cHRM chunk if set, else the historical + * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See + * png_do_rgb_to_gray for more discussion of the values. In this case + * the coefficients are not marked as 'set' and are not overwritten if + * something has already provided a default. */ if (png_ptr->rgb_to_gray_red_coeff == 0 && - png_ptr->rgb_to_gray_green_coeff == 0 && - png_ptr->rgb_to_gray_blue_coeff == 0) + png_ptr->rgb_to_gray_green_coeff == 0) { - png_ptr->rgb_to_gray_red_coeff = 6968; /* .212671 * 32768 + .5 */ - png_ptr->rgb_to_gray_green_coeff = 23434; /* .715160 * 32768 + .5 */ - png_ptr->rgb_to_gray_blue_coeff = 2366; + png_ptr->rgb_to_gray_red_coeff = 6968; + png_ptr->rgb_to_gray_green_coeff = 23434; + /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ } } } } @@ -1400,9 +1405,9 @@ */ if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) { /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if - * the file was greyscale the background value is gray. + * the file was grayscale the background value is gray. */ if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; } @@ -1634,9 +1639,9 @@ } /* Prevent the transformations being done again. * - * NOTE: this is highly dubious; it zaps the transformations in + * NOTE: this is highly dubious; it removes the transformations in * place. This seems inconsistent with the general treatment of the * transformations elsewhere. */ png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); @@ -3065,78 +3070,130 @@ #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Reduce RGB files to grayscale, with or without alpha - * using the equation given in Poynton's ColorFAQ at - * (THIS LINK IS DEAD June 2008) - * New link: - * + * using the equation given in Poynton's ColorFAQ of 1998-01-04 at + * (THIS LINK IS DEAD June 2008 but + * versions dated 1998 through November 2002 have been archived at + * http://web.archive.org/web/20000816232553/http://www.inforamp.net/ + * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) * Charles Poynton poynton at poynton.com * * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B * - * We approximate this with - * - * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - * * which can be expressed with integers as * * Y = (6969 * R + 23434 * G + 2365 * B)/32768 * - * The calculation is to be done in a linear colorspace. + * Poynton's current link (as of January 2003 through July 2011): + * + * has changed the numbers slightly: + * + * Y = 0.2126*R + 0.7152*G + 0.0722*B + * + * which can be expressed with integers as + * + * Y = (6966 * R + 23436 * G + 2366 * B)/32768 * - * Other integer coefficents can be used via png_set_rgb_to_gray(). + * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 + * end point chromaticities and the D65 white point. Depending on the + * precision used for the D65 white point this produces a variety of different + * numbers, however if the four decimal place value used in ITU-R Rec 709 is + * used (0.3127,0.3290) the Y calculation would be: + * + * Y = (6968 * R + 23435 * G + 2366 * B)/32768 + * + * While this is correct the rounding results in an overflow for white, because + * the sum of the rounded coefficients is 32769, not 32768. Consequently + * libpng uses, instead, the closest non-overflowing approximation: + * + * Y = (6968 * R + 23434 * G + 2366 * B)/32768 + * + * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk + * (including an sRGB chunk) then the chromaticities are used to calculate the + * coefficients. See the chunk handling in pngrutil.c for more information. + * + * In all cases the calculation is to be done in a linear colorspace. If no + * gamma information is available to correct the encoding of the original RGB + * values this results in an implicit assumption that the original PNG RGB + * values were linear. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). Because + * the API takes just red and green coefficients the blue coefficient is + * calculated to make the sum 32768. This will result in different rounding + * to that used above. */ int /* PRIVATE */ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) { - png_uint_32 i; - - png_uint_32 row_width = row_info->width; int rgb_error = 0; png_debug(1, "in png_do_rgb_to_gray"); if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) && (row_info->color_type & PNG_COLOR_MASK_COLOR)) { - png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; - png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; - png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; + PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + PNG_CONST png_uint_32 bc = 32768 - rc - gc; + PNG_CONST png_uint_32 row_width = row_info->width; + PNG_CONST int have_alpha = + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { if (row_info->bit_depth == 8) { #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* Notice that gamma to/from 1 are not necessarily inverses (if + * there is an overall gamma correction). Prior to 1.5.5 this code + * checked the linearized values for equality; this doesn't match + * the documentation, the original values must be checked. + */ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) { png_bytep sp = row; png_bytep dp = row; + png_uint_32 i; for (i = 0; i < row_width; i++) { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); if (red != green || red != blue) { + red = png_ptr->gamma_to_1[red]; + green = png_ptr->gamma_to_1[green]; + blue = png_ptr->gamma_to_1[blue]; + rgb_error |= 1; *(dp++) = png_ptr->gamma_from_1[ - (rc*red + gc*green + bc*blue)>>15]; + (rc*red + gc*green + bc*blue + 16384)>>15]; } else - *(dp++) = *(sp - 1); + { + /* If there is no overall correction the table will not be + * set. + */ + if (png_ptr->gamma_table != NULL) + red = png_ptr->gamma_table[red]; + + *(dp++) = red; + } + + if (have_alpha) + *(dp++) = *(sp++); } } else #endif { png_bytep sp = row; png_bytep dp = row; + png_uint_32 i; + for (i = 0; i < row_width; i++) { png_byte red = *(sp++); png_byte green = *(sp++); @@ -3144,25 +3201,32 @@ if (red != green || red != blue) { rgb_error |= 1; + /*NOTE: this is the historical approach which simply + * truncates the results. + */ *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); } else - *(dp++) = *(sp - 1); + *(dp++) = red; + + if (have_alpha) + *(dp++) = *(sp++); } } } else /* RGB bit_depth == 16 */ { #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) + if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) { png_bytep sp = row; png_bytep dp = row; + png_uint_32 i; + for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, w; @@ -3170,9 +3234,16 @@ green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; if (red == green && red == blue) + { + if (png_ptr->gamma_16_table != NULL) + w = png_ptr->gamma_16_table[(red&0xff) + >> png_ptr->gamma_shift][red>>8]; + + else w = red; + } else { png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) @@ -3182,23 +3253,31 @@ png_ptr->gamma_shift][green>>8]; png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> png_ptr->gamma_shift][blue>>8]; png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 - + bc*blue_1)>>15); + + bc*blue_1 + 16384)>>15); w = png_ptr->gamma_16_from_1[(gray16&0xff) >> png_ptr->gamma_shift][gray16 >> 8]; rgb_error |= 1; } *(dp++) = (png_byte)((w>>8) & 0xff); *(dp++) = (png_byte)(w & 0xff); + + if (have_alpha) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + } } } else #endif { png_bytep sp = row; png_bytep dp = row; + png_uint_32 i; + for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, gray16; @@ -3208,122 +3287,20 @@ if (red != green || red != blue) rgb_error |= 1; - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + /* From 1.5.5 in the 16 bit case do the accurate convertion even + * in the 'fast' case - this is because this is where the code + * ends up when handling linear 16 bit data. + */ + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> + 15); *(dp++) = (png_byte)((gray16>>8) & 0xff); *(dp++) = (png_byte)(gray16 & 0xff); - } - } - } - } - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; - - if (red != green || red != blue) - rgb_error |= 1; - - *(dp++) = png_ptr->gamma_from_1 - [(rc*red + gc*green + bc*blue)>>15]; - *(dp++) = *(sp++); /* alpha */ - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - if (red != green || red != blue) - rgb_error |= 1; - - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = *(sp++); /* alpha */ - } - } - } - else /* RGBA bit_depth == 16 */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - - if (red == green && red == blue) - w = red; - - else + if (have_alpha) { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> - png_ptr->gamma_shift][red>>8]; - - png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> - png_ptr->gamma_shift][blue>>8]; - - png_uint_16 gray16 = (png_uint_16)((rc * red_1 - + gc * green_1 + bc * blue_1)>>15); - - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - *(dp++) = *(sp++); /* alpha */ *(dp++) = *(sp++); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - red = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2; - - if (red != green || red != blue) - rgb_error |= 1; - - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - *(dp++) = *(sp++); /* alpha */ *(dp++) = *(sp++); } } } @@ -4761,9 +4739,9 @@ } #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED -/* If the bit depth is 8 and the colour type is not a palette type expand the +/* If the bit depth is 8 and the color type is not a palette type expand the * whole row to 16 bits. Has no effect otherwise. */ void /* PRIVATE */ png_do_expand_16(png_row_infop row_info, png_bytep row) diff -ru4NwbB libpng-1.5.4/pngrutil.c libpng-1.5.5beta07/pngrutil.c --- libpng-1.5.4/pngrutil.c 2011-07-07 06:24:48.352709758 -0500 +++ libpng-1.5.5beta07/pngrutil.c 2011-09-08 12:21:33.624212645 -0500 @@ -1,8 +1,8 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -457,9 +457,9 @@ #endif { /* Success (maybe) - really uncompress the chunk. */ png_size_t new_size = 0; - png_charp text = png_malloc_warn(png_ptr, + png_charp text = (png_charp)png_malloc_warn(png_ptr, prefix_size + expanded_size + 1); if (text != NULL) { @@ -500,9 +500,9 @@ * data, reallocate the chunkdata to remove the potentially large * amount of compressed data. */ { - png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); + png_charp text = (png_charp)png_malloc_warn(png_ptr, prefix_size + 1); if (text != NULL) { if (prefix_size > 0) @@ -1021,29 +1021,82 @@ #endif /* PNG_READ_sRGB_SUPPORTED */ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Store the _white values as default coefficients for the rgb to gray - * operation if it is supported. + * operation if it is supported. Check if the transform is already set to + * avoid destroying the transform values. */ - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + if (!png_ptr->rgb_to_gray_coefficients_set) { - /* png_set_background has not been called, the coefficients must be in - * range for the following to work without overflow. + /* png_set_background has not been called and we haven't seen an sRGB + * chunk yet. Find the XYZ of the three end points. + */ + png_XYZ XYZ; + png_xy xy; + + xy.redx = x_red; + xy.redy = y_red; + xy.greenx = x_green; + xy.greeny = y_green; + xy.bluex = x_blue; + xy.bluey = y_blue; + xy.whitex = x_white; + xy.whitey = y_white; + + if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy)) + { + /* The success case, because XYZ_from_xy normalises to a reference + * white Y of 1.0 we just need to scale the numbers. This should + * always work just fine. It is an internal error if this overflows. */ - if (y_red <= (1<<17) && y_green <= (1<<17) && y_blue <= (1<<17)) { - /* The y values are chromaticities: Y/X+Y+Z, the weights for the gray - * transformation are simply the normalized Y values for red, green and - * blue scaled by 32768. + png_fixed_point r, g, b; + if (png_muldiv(&r, XYZ.redY, 32768, PNG_FP_1) && + r >= 0 && r <= 32768 && + png_muldiv(&g, XYZ.greenY, 32768, PNG_FP_1) && + g >= 0 && g <= 32768 && + png_muldiv(&b, XYZ.blueY, 32768, PNG_FP_1) && + b >= 0 && b <= 32768 && + r+g+b <= 32769) + { + /* We allow 0 coefficients here. r+g+b may be 32769 if two or + * all of the coefficients were rounded up. Handle this by + * reducing the *largest* coefficient by 1; this matches the + * approach used for the default coefficients in pngrtran.c */ - png_uint_32 w = y_red + y_green + y_blue; + int add = 0; + + if (r+g+b > 32768) + add = -1; + else if (r+g+b < 32768) + add = 1; - png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red * - 32768)/w); - png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green - * 32768)/w); - png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue * - 32768)/w); + if (add != 0) + { + if (g >= r && g >= b) + g += add; + else if (r >= g && r >= b) + r += add; + else + b += add; + } + + /* Check for an internal error. */ + if (r+g+b != 32768) + png_error(png_ptr, + "internal error handling cHRM coefficients"); + + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + } + + /* This is a png_error at present even though it could be ignored - + * it should never happen, but it is important that if it does, the + * bug is fixed. + */ + else + png_error(png_ptr, "internal error handling cHRM->XYZ"); + } } } #endif @@ -1134,8 +1187,49 @@ "Ignoring incorrect cHRM value when sRGB is also present"); } #endif /* PNG_READ_cHRM_SUPPORTED */ + /* This is recorded for use when handling the cHRM chunk above. An sRGB + * chunk unconditionally overwrites the coefficients for grayscale conversion + * too. + */ + png_ptr->is_sRGB = 1; + +# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Don't overwrite user supplied values: */ + if (!png_ptr->rgb_to_gray_coefficients_set) + { + /* These numbers come from the sRGB specification (or, since one has to + * pay much money to get a copy, the wikipedia sRGB page) the + * chromaticity values quoted have been inverted to get the reverse + * transformation from RGB to XYZ and the 'Y' coefficients scaled by + * 32768 (then rounded). + * + * sRGB and ITU Rec-709 both truncate the values for the D65 white + * point to four digits and, even though it actually stores five + * digits, the PNG spec gives the truncated value. + * + * This means that when the chromaticities are converted back to XYZ + * end points we end up with (6968,23435,2366), which, as described in + * pngrtran.c, would overflow. If the five digit precision and up is + * used we get, instead: + * + * 6968*R + 23435*G + 2365*B + * + * (Notice that this rounds the blue coefficient down, rather than the + * choice used in pngrtran.c which is to round the green one down.) + */ + png_ptr->rgb_to_gray_red_coeff = 6968; /* 0.212639005871510 */ + png_ptr->rgb_to_gray_green_coeff = 23434; /* 0.715168678767756 */ + /* png_ptr->rgb_to_gray_blue_coeff = 2366; 0.072192315360734 */ + + /* The following keeps the cHRM chunk from destroying the + * coefficients again in the event that it follows the sRGB chunk. + */ + png_ptr->rgb_to_gray_coefficients_set = 1; + } +# endif + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); } #endif /* PNG_READ_sRGB_SUPPORTED */ diff -ru4NwbB libpng-1.5.4/pngset.c libpng-1.5.5beta07/pngset.c --- libpng-1.5.4/pngset.c 2011-07-07 06:24:48.360972928 -0500 +++ libpng-1.5.5beta07/pngset.c 2011-09-08 12:21:33.635715416 -0500 @@ -1,8 +1,8 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -63,8 +63,41 @@ info_ptr->valid |= PNG_INFO_cHRM; } } +void PNGFAPI +png_set_cHRM_XYZ_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z) +{ + png_XYZ XYZ; + png_xy xy; + + png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + XYZ.redX = int_red_X; + XYZ.redY = int_red_Y; + XYZ.redZ = int_red_Z; + XYZ.greenX = int_green_X; + XYZ.greenY = int_green_Y; + XYZ.greenZ = int_green_Z; + XYZ.blueX = int_blue_X; + XYZ.blueY = int_blue_Y; + XYZ.blueZ = int_blue_Z; + + if (png_xy_from_XYZ(&xy, XYZ)) + png_error(png_ptr, "XYZ values out of representable range"); + + png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy, + xy.greenx, xy.greeny, xy.bluex, xy.bluey); +} + # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_cHRM(png_structp png_ptr, png_infop info_ptr, double white_x, double white_y, double red_x, double red_y, @@ -79,8 +112,25 @@ png_fixed(png_ptr, green_y, "cHRM Green Y"), png_fixed(png_ptr, blue_x, "cHRM Blue X"), png_fixed(png_ptr, blue_y, "cHRM Blue Y")); } + +void PNGAPI +png_set_cHRM_XYZ(png_structp png_ptr, png_infop info_ptr, double red_X, + double red_Y, double red_Z, double green_X, double green_Y, double green_Z, + double blue_X, double blue_Y, double blue_Z) +{ + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, red_X, "cHRM Red X"), + png_fixed(png_ptr, red_Y, "cHRM Red Y"), + png_fixed(png_ptr, red_Z, "cHRM Red Z"), + png_fixed(png_ptr, green_X, "cHRM Red X"), + png_fixed(png_ptr, green_Y, "cHRM Red Y"), + png_fixed(png_ptr, green_Z, "cHRM Red Z"), + png_fixed(png_ptr, blue_X, "cHRM Red X"), + png_fixed(png_ptr, blue_Y, "cHRM Red Y"), + png_fixed(png_ptr, blue_Z, "cHRM Red Z")); +} # endif /* PNG_FLOATING_POINT_SUPPORTED */ #endif /* PNG_cHRM_SUPPORTED */ @@ -98,9 +148,9 @@ * occur. Since the fixed point representation is assymetrical it is * possible for 1/gamma to overflow the limit of 21474 and this means the * gamma value must be at least 5/100000 and hence at most 20000.0. For * safety the limits here are a little narrower. The values are 0.00016 to - * 6250.0, which are truely ridiculous gammma values (and will produce + * 6250.0, which are truly ridiculous gammma values (and will produce * displays that are all black or all white.) */ if (file_gamma < 16 || file_gamma > 625000000) png_warning(png_ptr, "Out of range gamma value ignored"); diff -ru4NwbB libpng-1.5.4/pngstruct.h libpng-1.5.5beta07/pngstruct.h --- libpng-1.5.4/pngstruct.h 2011-07-07 06:24:48.248857565 -0500 +++ libpng-1.5.5beta07/pngstruct.h 2011-09-08 12:21:33.520192593 -0500 @@ -4,9 +4,9 @@ * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h @@ -254,15 +254,22 @@ int num_chunk_list; png_bytep chunk_list; #endif +#ifdef PNG_READ_sRGB_SUPPORTED + /* Added in 1.5.5 to record an sRGB chunk in the png. */ + png_byte is_sRGB; +#endif + /* New members added in libpng-1.0.3 */ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte rgb_to_gray_status; + /* Added in libpng 1.5.5 to record setting of coefficients: */ + png_byte rgb_to_gray_coefficients_set; /* These were changed from png_byte in libpng-1.0.6 */ png_uint_16 rgb_to_gray_red_coeff; png_uint_16 rgb_to_gray_green_coeff; - png_uint_16 rgb_to_gray_blue_coeff; + /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ #endif /* New member added in libpng-1.0.4 (renamed in 1.0.9) */ #if defined(PNG_MNG_FEATURES_SUPPORTED) || \ diff -ru4NwbB libpng-1.5.4/pngvalid.c libpng-1.5.5beta07/pngvalid.c --- libpng-1.5.4/pngvalid.c 2011-07-07 06:24:48.403347080 -0500 +++ libpng-1.5.5beta07/pngvalid.c 2011-09-08 12:21:33.680037063 -0500 @@ -1,8 +1,8 @@ /* pngvalid.c - validate libpng by constructing then reading png files. * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.5.5 [(PENDING RELEASE)] * Copyright (c) 2011 Glenn Randers-Pehrson * Written by John Cunningham Bowler * * This code is released under the libpng license. @@ -52,10 +52,11 @@ #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 * 100000)) + ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) #endif #include "zlib.h" /* For crc32 */ @@ -76,8 +77,17 @@ #endif /***************************** EXCEPTION HANDLING *****************************/ #include "contrib/visupng/cexcept.h" + +#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 @@ -128,12 +138,20 @@ static PNG_CONST char sep[] = ": "; static PNG_CONST char *colour_types[8] = { - "greyscale", invalid, "truecolour", "indexed-colour", - "greyscale with alpha", invalid, "truecolour with alpha", invalid + "grayscale", invalid, "truecolour", "indexed-colour", + "grayscale with alpha", invalid, "truecolour with alpha", invalid }; +/* 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; +} + /* 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 @@ -142,9 +160,9 @@ 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 = /*no cast required*/pv; + 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. */ @@ -178,8 +196,28 @@ } #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 */ +} + +static int +random_choice(void) +{ + unsigned char x; + + RANDOMIZE(x); + + return x & 1; +} + /* 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.) @@ -630,9 +668,9 @@ if (ps->writepos != STORE_BUFFER_SIZE) png_error(ps->pwrite, "invalid store call"); - pb = malloc(sizeof *pb); + pb = voidcast(png_store_buffer*, malloc(sizeof *pb)); if (pb == NULL) png_error(ps->pwrite, "store new: OOM"); @@ -666,9 +704,9 @@ */ static void store_storefile(png_store *ps, png_uint_32 id) { - png_store_file *pf = malloc(sizeof *pf); + 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; @@ -760,9 +798,9 @@ /* Functions to use as PNG callbacks. */ static void store_error(png_structp pp, png_const_charp message) /* PNG_NORETURN */ { - png_store *ps = png_get_error_ptr(pp); + png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); if (!ps->expect_error) store_log(ps, pp, message, 1 /* error */); @@ -775,9 +813,9 @@ static void store_warning(png_structp pp, png_const_charp message) { - png_store *ps = png_get_error_ptr(pp); + png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); if (!ps->expect_warning) store_log(ps, pp, message, 0 /* warning */); else @@ -837,9 +875,9 @@ store_image_free(ps, pp); /* The buffer is deliberately mis-aligned. */ - image = malloc(cb+2); + image = voidcast(png_bytep, malloc(cb+2)); if (image == NULL) { /* Called from the startup - ignore the error for the moment. */ if (pp == NULL) @@ -921,9 +959,9 @@ static void store_write(png_structp pp, png_bytep pb, png_size_t st) { - png_store *ps = png_get_io_ptr(pp); + png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); if (ps->pwrite != pp) png_error(pp, "store state damaged"); @@ -1041,9 +1079,9 @@ static void store_read(png_structp pp, png_bytep pb, png_size_t st) { - png_store *ps = png_get_io_ptr(pp); + png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); if (ps == NULL || ps->pread != pp) png_error(pp, "bad store read call"); @@ -1081,9 +1119,10 @@ /* This function can only return NULL if called with '0'! */ if (npalette > 0) { - ps->palette = malloc(npalette * sizeof *ps->palette); + ps->palette = voidcast(store_palette_entry*, malloc(npalette * + sizeof *ps->palette)); if (ps->palette == NULL) png_error(ps->pwrite, "store new palette: OOM"); @@ -1228,10 +1267,11 @@ /* The memory callbacks: */ static png_voidp store_malloc(png_structp pp, png_alloc_size_t cb) { - store_pool *pool = png_get_mem_ptr(pp); - store_memory *new = malloc(cb + (sizeof *new) + (sizeof pool->mark)); + 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) @@ -1261,10 +1301,10 @@ static void store_free(png_structp pp, png_voidp memory) { - store_pool *pool = png_get_mem_ptr(pp); - store_memory *this = memory, **test; + store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp)); + store_memory *this = voidcast(store_memory*, memory), **test; /* 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. */ @@ -1482,19 +1522,127 @@ * 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; + +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); +} + +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; + +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; +} + +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; + } +} + +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; +} + typedef struct png_modifier { png_store this; /* I am a png_store */ struct png_modification *modifications; /* Changes to make */ - enum modifier_state - { - modifier_start, /* Initial value */ - modifier_signature, /* Have a signature */ - modifier_IHDR /* Have an IHDR */ - } state; /* My state */ + modifier_state state; /* My state */ /* Information from IHDR: */ png_byte bit_depth; /* From IHDR */ png_byte colour_type; /* From IHDR */ @@ -1507,8 +1655,22 @@ /* 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; @@ -1523,8 +1685,15 @@ 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 */ @@ -1574,8 +1743,9 @@ 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 @@ -1604,11 +1774,21 @@ 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; @@ -1626,8 +1806,9 @@ 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 */ } @@ -1637,11 +1818,37 @@ * 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! + * to a calculation - not a digitization operation - unless the following API is + * called directly. */ -static double abserr(png_modifier *pm, int in_depth, int out_depth) +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; +} + +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. */ @@ -1651,9 +1858,9 @@ else return pm->maxabs8; } -static double calcerr(png_modifier *pm, int in_depth, int out_depth) +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). */ @@ -1663,9 +1870,9 @@ else return pm->maxcalc8; } -static double pcerr(png_modifier *pm, int in_depth, int out_depth) +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. */ @@ -1686,13 +1893,13 @@ * * The specified parameter does *not* include the base .5 digitization error but * it is added here. */ -static double outerr(png_modifier *pm, int in_depth, int out_depth) +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 greyscale gamma is up to the value below. This is a hack + * 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 */ @@ -1719,9 +1926,9 @@ /* 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_modifier *pm, int in_depth, int out_depth) +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: */ @@ -1758,9 +1965,9 @@ * 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_modifier *pm, int in_depth, +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) @@ -1796,9 +2003,10 @@ unsigned int added :1; /* Chunk was added */ unsigned int removed :1; /* Chunk was removed */ } png_modification; -static void modification_reset(png_modification *pmm) +static void +modification_reset(png_modification *pmm) { if (pmm != NULL) { pmm->modified = 0; @@ -1819,16 +2027,176 @@ modification_reset(pmm); } 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; +} + +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; - pm->pending_len = pm->pending_chunk = 0; - pm->flush = pm->buffer_count = pm->buffer_position = 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)) @@ -2071,9 +2439,9 @@ /* The callback: */ static void modifier_read(png_structp pp, png_bytep pb, png_size_t st) { - png_modifier *pm = png_get_io_ptr(pp); + 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"); @@ -2090,9 +2458,9 @@ 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 truely horrible variable + * 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. */ @@ -2157,8 +2525,207 @@ 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; +} + +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_TRANSFORMS_SUPPORTED */ /***************************** STANDARD PNG FILES *****************************/ /* Standard files - write and save standard files. */ @@ -2223,9 +2790,9 @@ values[i][2] = (i&2) ? 255 : 0; values[i][3] = (i&4) ? 255 : 0; } - /* Then add 62 greys (one quarter of the remaining 256 slots). */ + /* Then add 62 grays (one quarter of the remaining 256 slots). */ { int j = 0; png_byte random_bytes[4]; png_byte need[256]; @@ -2254,9 +2821,9 @@ } } /* 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 greys, + * 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) @@ -3322,8 +3889,10 @@ static void standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id, int do_interlace) { + memset(dp, 0, sizeof *dp); + dp->ps = ps; dp->colour_type = COL_FROM_ID(id); dp->bit_depth = DEPTH_FROM_ID(id); if (dp->colour_type == 3) @@ -3428,10 +3997,10 @@ 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 zap the trans_alpha pointer, only num_trans, so - * in the above call we get a success, we get a pointer (who knows what + * 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. */ { @@ -3710,9 +4279,10 @@ static void standard_info(png_structp pp, png_infop pi) { - standard_display *dp = png_get_progressive_ptr(pp); + standard_display *dp = voidcast(standard_display*, + png_get_progressive_ptr(pp)); /* Call with nImages==1 because the progressive reader can only produce one * image. */ @@ -3721,9 +4291,10 @@ static void progressive_row(png_structp pp, png_bytep new_row, png_uint_32 y, int pass) { - PNG_CONST standard_display *dp = png_get_progressive_ptr(pp); + 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 @@ -3896,9 +4467,10 @@ static void standard_end(png_structp pp, png_infop pi) { - standard_display *dp = png_get_progressive_ptr(pp); + standard_display *dp = voidcast(standard_display*, + png_get_progressive_ptr(pp)); UNUSED(pi) /* Validate the image - progressive reading only produces one variant for @@ -4118,9 +4690,9 @@ 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 greyscale test. + * compared to the grayscale test. */ #if 0 if (!test_size(pm, 3, 0, 3)) return; @@ -4289,9 +4861,9 @@ * 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, const standard_display *display) +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); @@ -4375,9 +4947,15 @@ /* A single transform for the image, expressed as a series of function * callbacks and some space for values. * - * First a callback to set the transform on the current png_read_struct: + * 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); @@ -4411,14 +4989,50 @@ /* Local variables */ png_byte output_colour_type; png_byte output_bit_depth; - /* Variables for the individual transforms. */ - /* png_set_background */ - image_pixel background_colour; + /* Modifications (not necessarily used.) */ + gama_modification gama_mod; + chrm_modification chrm_mod; + srgb_modification srgb_mod; } transform_display; -/* Two functions to end the list: */ +/* 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) { @@ -4512,8 +5126,9 @@ 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! */ }; @@ -4524,8 +5139,10 @@ 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*/); /* Parameter fields */ @@ -4656,27 +5273,28 @@ static void transform_info(png_structp pp, png_infop pi) { - transform_info_imp(png_get_progressive_ptr(pp), pp, pi); + transform_info_imp(voidcast(transform_display*, png_get_progressive_ptr(pp)), + pp, pi); } static void transform_range_check(png_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, PNG_CONST char *name, - double digitization_error) + 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 (the threshold is about 1/255.) + * internal errors in pngvalid itself. */ unsigned int max = (1U< 4E-3 || !(out >= in_min && out <= in_max)) + if (err > limit || !(out >= in_min && out <= in_max)) { char message[256]; size_t pos; @@ -4829,28 +5447,32 @@ * 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, "red/gray", + 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, 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, name); + pp = set_modifier_for_read(d.pm, &pi, d.this.id, full_name); standard_palette_init(&d.this); # if 0 /* Logging (debugging only) */ @@ -4926,13 +5563,17 @@ 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,\ @@ -4940,15 +5581,23 @@ &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); +} + static int image_transform_default_add(image_transform *this, PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) { @@ -5367,59 +6016,328 @@ 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; + 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; - this->next->mod(this->next, that, pp, display); + 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; } -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) + else { - UNUSED(bit_depth) - - this->next = *that; - *that = this; + data.red_to_set = -1; + data.green_to_set = -1; + } - return (colour_type & PNG_COLOR_MASK_ALPHA) != 0; + /* 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); } -IT(strip_alpha); -#undef PT -#define PT ITSTRUCT(strip_alpha) -#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */ + 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); + } + } -#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 - * - * At present the APIs are simply tested using the 16.16 fixed point conversion - * values known to be used inside libpng: - * - * red: 6968 - * green: 23434 - * blue: 2366 - * - * NOTE: this currently ignores the gamma because no gamma is being set, the - * tests on gamma need to happen in the gamma test set. + 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, -1, -1); + 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, -1, -1); + 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 @@ -5427,26 +6345,155 @@ image_pixel *that, png_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... */ - that->bluef = that->greenf = that->redf = (that->redf * 6968 + - that->greenf * 23434 + that->bluef * 2366) / 32768; - that->bluee = that->greene = that->rede = (that->rede * 6968 + - that->greene * 23434 + that->bluee * 2366) / 32768 * - (1 + DBL_EPSILON * 6); + { + 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 zap the colour bit in the type: */ + /* 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; @@ -5466,11 +6513,14 @@ 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, @@ -5478,10 +6528,13 @@ * 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. + * 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) { @@ -5508,9 +6561,9 @@ else bit_depth = that->this.bit_depth; - image_pixel_init(&that->background_colour, random_bytes, colour_type, + 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. @@ -5518,15 +6571,15 @@ RANDOMIZE(back); if (colour_type & PNG_COLOR_MASK_COLOR) { - back.red = (png_uint_16)that->background_colour.red; - back.green = (png_uint_16)that->background_colour.green; - back.blue = (png_uint_16)that->background_colour.blue; + 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)that->background_colour.red; + 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); @@ -5548,38 +6601,36 @@ /* This is only necessary if the alpha value is less than 1. */ if (that->alphaf < 1) { - PNG_CONST image_pixel *back = &display->background_colour; - /* Now we do the background calculation without any gamma correction. */ if (that->alphaf <= 0) { - that->redf = back->redf; - that->greenf = back->greenf; - that->bluef = back->bluef; - - that->rede = back->rede; - that->greene = back->greene; - that->bluee = back->bluee; - - that->red_sBIT= back->red_sBIT; - that->green_sBIT= back->green_sBIT; - that->blue_sBIT= back->blue_sBIT; + 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 + back->redf * alf; - that->rede = that->rede * that->alphaf + back->rede * alf + + 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 + back->greenf * alf; - that->greene = that->greene * that->alphaf + back->greene * alf + + 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 + back->bluef * alf; - that->bluee = that->bluee * that->alphaf + back->bluee * alf + + 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.) */ @@ -5597,8 +6648,9 @@ } #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 */ @@ -5754,9 +6806,9 @@ } else { - /* Not useful and max>0, so remvoe it from *this: */ + /* 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 @@ -5885,161 +6937,25 @@ 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 -/* Gamma test images. */ -typedef struct gamma_modification -{ - png_modification this; - png_fixed_point gamma; -} gamma_modification; - -static int -gamma_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, ((gamma_modification*)me)->gamma); - return 1; -} - -static void -gamma_modification_init(gamma_modification *me, png_modifier *pm, double gammad) -{ - double g; - - modification_init(&me->this); - me->this.chunk = CHUNK_gAMA; - me->this.modify_fn = gamma_modify; - me->this.add = CHUNK_PLTE; - g = floor(gammad * 100000 + .5); - me->gamma = (png_fixed_point)g; - 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; -} - -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; -} - /* Reader callbacks and implementations, where they differ from the standard * ones. */ typedef struct gamma_display @@ -6139,9 +7055,9 @@ * 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 = (png_fixed_point)(sg*100000+.5); + PNG_CONST png_fixed_point g = fix(sg); # endif # ifdef PNG_FLOATING_POINT_SUPPORTED png_set_alpha_mode(pp, mode, sg); @@ -6157,9 +7073,9 @@ { # ifdef PNG_FLOATING_POINT_SUPPORTED png_set_gamma(pp, sg, dp->file_gamma); # else - png_fixed_point f = (png_fixed_point)(dp->file_gamma*100000+.5); + png_fixed_point f = fix(dp->file_gamma); png_set_gamma_fixed(pp, g, f); # endif } } @@ -6174,10 +7090,10 @@ # ifdef PNG_FLOATING_POINT_SUPPORTED png_set_gamma(pp, dp->screen_gamma, dp->file_gamma); # else { - png_fixed_point s = (png_fixed_point)(dp->screen_gamma*100000+.5); - png_fixed_point f = (png_fixed_point)(dp->file_gamma*100000+.5); + png_fixed_point s = fix(dp->screen_gamma); + png_fixed_point f = fix(dp->file_gamma); png_set_gamma_fixed(pp, s, f); } # endif @@ -6187,9 +7103,9 @@ /* 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 = (png_fixed_point)(bg*100000+.5); + PNG_CONST png_fixed_point g = fix(bg); # endif # ifdef PNG_FLOATING_POINT_SUPPORTED png_set_background(pp, &dp->background_color, dp->do_background, @@ -6212,9 +7128,10 @@ static void gamma_info(png_structp pp, png_infop pi) { - gamma_info_imp(png_get_progressive_ptr(pp), pp, 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 @@ -7106,10 +8023,10 @@ alpha /= vi.sbit_max; } } - /* Handle greyscale or RGB components. */ - if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* greyscale */ + /* 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); @@ -7155,9 +8072,9 @@ static void gamma_end(png_structp pp, png_infop pi) { - gamma_display *dp = png_get_progressive_ptr(pp); + gamma_display *dp = voidcast(gamma_display*, png_get_progressive_ptr(pp)); if (!dp->this.speed) gamma_image_validate(dp, pp, pi); } @@ -7191,17 +8108,22 @@ Try { png_structp pp; png_infop pi; - gamma_modification gamma_mod; + 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; - gamma_modification_init(&gamma_mod, d.pm, d.file_gamma); + 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); @@ -7409,9 +8331,10 @@ while (next_format(&colour_type, &bit_depth, &palette_number)) { unsigned int i, j; - for (i=0; ingammas; ++i) for (j=0; jngammas; ++j) if (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*/); @@ -7444,13 +8367,13 @@ (colour_type != 3 && sbit < bit_depth))) { unsigned int i; - for (i=0; ingammas; ++i) + for (i=0; ingamma_tests; ++i) { unsigned int j; - for (j=0; jngammas; ++j) if (i != 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*/); @@ -7481,11 +8404,11 @@ * 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; ingammas; ++i) + for (i=0; ingamma_tests; ++i) { - for (j=0; jngammas; ++j) + for (j=0; jngamma_tests; ++j) { if (i != j && fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD) { @@ -7662,9 +8585,9 @@ { unsigned int i, j; /* Don't skip the i==j case here - it's relevant. */ - for (i=0; ingammas; ++i) for (j=0; jngammas; ++j) + 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); @@ -8178,8 +9101,43 @@ } } } +/* 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} }, +}; + /* main program */ int main(int argc, PNG_CONST char **argv) { volatile int summary = 1; /* Print the error summary at the end */ @@ -8219,9 +9177,15 @@ pm.this.treat_warnings_as_errors = 1; /* Store the test gammas */ pm.gammas = gammas; - pm.ngammas = 0; /* default to off */ + 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. @@ -8276,10 +9240,10 @@ else if (strcmp(*argv, "-w") == 0) pm.this.treat_warnings_as_errors = 0; else if (strcmp(*argv, "--speed") == 0) - pm.this.speed = 1, pm.ngammas = (sizeof gammas)/(sizeof gammas[0]), - pm.test_standard = 0, summary = 0; + pm.this.speed = 1, pm.ngamma_tests = pm.ngammas, pm.test_standard = 0, + summary = 0; else if (strcmp(*argv, "--memory") == 0) memstats = 1; @@ -8319,9 +9283,9 @@ else if (strcmp(*argv, "--gamma") == 0) { /* Just do two gamma tests here (2.2 and linear) for speed: */ - pm.ngammas = 2U; + pm.ngamma_tests = 2U; pm.test_gamma_threshold = 1; pm.test_gamma_transform = 1; pm.test_gamma_sbit = 1; pm.test_gamma_scale16 = 1; @@ -8329,42 +9293,42 @@ pm.test_gamma_alpha_mode = 1; } else if (strcmp(*argv, "--nogamma") == 0) - pm.ngammas = 0; + pm.ngamma_tests = 0; else if (strcmp(*argv, "--gamma-threshold") == 0) - pm.ngammas = 2U, pm.test_gamma_threshold = 1; + 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.ngammas = 2U, pm.test_gamma_transform = 1; + 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.ngammas = 2U, pm.test_gamma_sbit = 1; + 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.ngammas = 2U, pm.test_gamma_scale16 = 1; + 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.ngammas = 2U, pm.test_gamma_background = 1; + 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.ngammas = 2U, pm.test_gamma_alpha_mode = 1; + pm.ngamma_tests = 2U, pm.test_gamma_alpha_mode = 1; else if (strcmp(*argv, "--nogamma-alpha-mode") == 0) pm.test_gamma_alpha_mode = 0; @@ -8374,12 +9338,12 @@ else if (strcmp(*argv, "--noexpand16") == 0) pm.test_gamma_expand16 = 0; else if (strcmp(*argv, "--more-gammas") == 0) - pm.ngammas = 3U; + pm.ngamma_tests = 3U; else if (strcmp(*argv, "--all-gammas") == 0) - pm.ngammas = (sizeof gammas)/(sizeof gammas[0]); + pm.ngamma_tests = pm.ngammas; else if (strcmp(*argv, "--progressive-read") == 0) pm.this.progressive = 1; @@ -8398,8 +9362,11 @@ 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) @@ -8464,9 +9431,9 @@ /* 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.ngammas == 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 @@ -8474,12 +9441,12 @@ */ pm.test_standard = 1; pm.test_size = 1; pm.test_transform = 1; - pm.ngammas = 2U; + pm.ngamma_tests = 2U; } - if (pm.ngammas > 0 && + 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) { @@ -8490,9 +9457,9 @@ pm.test_gamma_background = 1; pm.test_gamma_alpha_mode = 1; } - else if (pm.ngammas == 0) + else if (pm.ngamma_tests == 0) { /* Nothing to test so turn everything off: */ pm.test_gamma_threshold = 0; pm.test_gamma_transform = 0; @@ -8529,9 +9496,9 @@ perform_transform_test(&pm); #endif /* PNG_READ_TRANSFORMS_SUPPORTED */ #ifdef PNG_READ_GAMMA_SUPPORTED - if (pm.ngammas > 0) + if (pm.ngamma_tests > 0) perform_gamma_test(&pm, summary); #endif } diff -ru4NwbB libpng-1.5.4/projects/vstudio/libpng/libpng.vcxproj libpng-1.5.5beta07/projects/vstudio/libpng/libpng.vcxproj --- libpng-1.5.4/projects/vstudio/libpng/libpng.vcxproj 2011-07-07 06:24:50.602473325 -0500 +++ libpng-1.5.5beta07/projects/vstudio/libpng/libpng.vcxproj 2011-09-08 12:21:35.849600686 -0500 @@ -117,9 +117,9 @@ false ProgramDatabase Disabled EnableFastChecks - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) true true false false @@ -174,9 +174,9 @@ ProgramDatabase MultiThreaded true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) false false pngpriv.h true diff -ru4NwbB libpng-1.5.4/projects/vstudio/pngvalid/pngvalid.vcxproj libpng-1.5.5beta07/projects/vstudio/pngvalid/pngvalid.vcxproj --- libpng-1.5.4/projects/vstudio/pngvalid/pngvalid.vcxproj 2011-07-07 06:24:50.622659908 -0500 +++ libpng-1.5.5beta07/projects/vstudio/pngvalid/pngvalid.vcxproj 2011-09-08 12:21:35.870219922 -0500 @@ -80,9 +80,9 @@ false ProgramDatabase Disabled EnableFastChecks - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_CONSOLE;PNG_USE_DLL;%(PreprocessorDefinitions) $(ZLibSrcDir);..\..\..\scripts;%(AdditionalIncludeDirectories) 4996;4127 false true @@ -145,9 +145,9 @@ ProgramDatabase Full false true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;PNG_USE_DLL;%(PreprocessorDefinitions) $(ZLibSrcDir);..\..\..\scripts;%(AdditionalIncludeDirectories) 4996;4127 false true diff -ru4NwbB libpng-1.5.4/projects/vstudio/zlib/zlib.vcxproj libpng-1.5.5beta07/projects/vstudio/zlib/zlib.vcxproj --- libpng-1.5.4/projects/vstudio/zlib/zlib.vcxproj 2010-08-24 15:04:11.000000000 -0500 +++ libpng-1.5.5beta07/projects/vstudio/zlib/zlib.vcxproj 2011-08-16 19:34:41.840659000 -0500 @@ -83,9 +83,9 @@ true - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreadedDebug TurnOffAllWarnings ProgramDatabase Disabled @@ -98,9 +98,9 @@ - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) TurnOffAllWarnings ProgramDatabase Disabled true @@ -155,9 +155,9 @@ - WIN32;NDEBUG;_WINDOWS;_USRDLL;DEBUGZLIB_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) Level3 ProgramDatabase diff -ru4NwbB libpng-1.5.4/scripts/makefile.darwin libpng-1.5.5beta07/scripts/makefile.darwin --- libpng-1.5.4/scripts/makefile.darwin 2011-07-07 06:24:50.251028311 -0500 +++ libpng-1.5.5beta07/scripts/makefile.darwin 2011-09-08 12:21:35.453764372 -0500 @@ -36,12 +36,13 @@ MKDIR_P=mkdir -p LN_SF=ln -sf RANLIB=ranlib RM_F=/bin/rm -f +ARCH="-arch i386 -arch x86_64" # CFLAGS=-I$(ZLIBINC) -W -Wall -O3 -funroll-loops -CFLAGS=-I$(ZLIBINC) -W -Wall -O -funroll-loops -LDFLAGS=-L. -L$(ZLIBLIB) -lpng%NN% -lz +CFLAGS=-I$(ZLIBINC) -W -Wall -O -funroll-loops $(ARCH) +LDFLAGS=-L. -L$(ZLIBLIB) -lpng%NN% -lz $(ARCH) INCPATH=$(prefix)/include LIBPATH=$(exec_prefix)/lib MANPATH=$(prefix)/man diff -ru4NwbB libpng-1.5.4/scripts/symbols.def libpng-1.5.5beta07/scripts/symbols.def --- libpng-1.5.4/scripts/symbols.def 2011-07-07 06:24:50.555507703 -0500 +++ libpng-1.5.5beta07/scripts/symbols.def 2011-09-08 12:21:35.804819839 -0500 @@ -234,4 +234,8 @@ png_set_text_compression_method @226 png_set_alpha_mode @227 png_set_alpha_mode_fixed @228 png_set_scale_16 @229 + png_get_cHRM_XYZ @230 + png_get_cHRM_XYZ_fixed @231 + png_set_cHRM_XYZ @232 + png_set_cHRM_XYZ_fixed @233