diff options
Diffstat (limited to 'contrib')
37 files changed, 916 insertions, 7155 deletions
diff --git a/contrib/examples/pngpixel.c b/contrib/examples/pngpixel.c index d82ef83d0..108e68696 100644 --- a/contrib/examples/pngpixel.c +++ b/contrib/examples/pngpixel.c @@ -103,7 +103,7 @@ print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row, index < num_trans ? trans_alpha[index] : 255); else /* no transparency */ - printf("INDEXED %u = %d %d %d\n", index, + printf("INDEXED %u = %d %d %d\n", index, palette[index].red, palette[index].green, palette[index].blue); } @@ -273,7 +273,7 @@ int main(int argc, const char **argv) ystep = xstep = 1; } - /* To find the pixel, loop over 'py' for each pass + /* To find the pixel loop over 'py' for each pass * reading a row and then checking to see if it * contains the pixel. */ @@ -283,13 +283,12 @@ int main(int argc, const char **argv) /* png_read_row takes two pointers. When libpng * handles the interlace the first is filled in - * pixel-by-pixel, and the second receives the same + * pixel-by-pixel, the second receives the same * pixels but they are replicated across the * unwritten pixels so far for each pass. When we * do the interlace, however, they just contain * the pixels from the interlace pass - giving - * both is wasteful and pointless, so we pass a - * NULL pointer. + * both is wasteful and pointless. */ png_read_row(png_ptr, row_tmp, NULL); @@ -327,7 +326,7 @@ int main(int argc, const char **argv) else { /* Else libpng has raised an error. An error message has - * already been output, so it is only necessary to clean up + * already been output, it is only necessary to clean up * locally allocated data: */ if (row != NULL) diff --git a/contrib/examples/pngtopng.c b/contrib/examples/pngtopng.c index b1b3be677..352a727a4 100644 --- a/contrib/examples/pngtopng.c +++ b/contrib/examples/pngtopng.c @@ -29,17 +29,13 @@ int main(int argc, const char **argv) { png_image image; - /* Only the image structure version number needs to be set. */ memset(&image, 0, sizeof image); - image.version = PNG_IMAGE_VERSION; if (png_image_begin_read_from_file(&image, argv[1])) { png_bytep buffer; - - /* Change this to try different formats! If you set a colormap format - * then you must also supply a colormap below. - */ + + /* Change this to try different formats! */ image.format = PNG_FORMAT_RGBA; buffer = malloc(PNG_IMAGE_SIZE(image)); @@ -47,11 +43,10 @@ int main(int argc, const char **argv) if (buffer != NULL) { if (png_image_finish_read(&image, NULL/*background*/, buffer, - 0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */)) + 0/*row_stride*/)) { if (png_image_write_to_file(&image, argv[2], - 0/*convert_to_8bit*/, buffer, 0/*row_stride*/, - NULL/*colormap*/)) + 0/*convert_to_8bit*/, buffer, 0/*row_stride*/)) result = 0; else diff --git a/contrib/gregbook/readpng.c b/contrib/gregbook/readpng.c index f5e1fb1a4..0b75fac6d 100644 --- a/contrib/gregbook/readpng.c +++ b/contrib/gregbook/readpng.c @@ -215,10 +215,6 @@ uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) * libpng function */ if (setjmp(png_jmpbuf(png_ptr))) { - free(image_data); - image_data = NULL; - free(row_pointers); - row_pointers = NULL; png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } diff --git a/contrib/gregbook/readpng2.c b/contrib/gregbook/readpng2.c index e179db71e..b9746b756 100644 --- a/contrib/gregbook/readpng2.c +++ b/contrib/gregbook/readpng2.c @@ -136,23 +136,29 @@ int readpng2_init(mainprog_info *mainprog_ptr) * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT, * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */ { - /* These byte strings were copied from png.h. If a future version - * of readpng2.c recognizes more chunks, add them to this list. - */ - static PNG_CONST png_byte chunks_to_process[] = { - 98, 75, 71, 68, '\0', /* bKGD */ - 103, 65, 77, 65, '\0', /* gAMA */ - 115, 82, 71, 66, '\0', /* sRGB */ - }; - - /* Ignore all chunks except for IHDR, PLTE, tRNS, IDAT, and IEND */ - png_set_keep_unknown_chunks(png_ptr, -1 /* PNG_HANDLE_CHUNK_NEVER */, - NULL, -1); - - /* But do not ignore chunks in the "chunks_to_process" list */ - png_set_keep_unknown_chunks(png_ptr, - 0 /* PNG_HANDLE_CHUNK_AS_DEFAULT */, chunks_to_process, - sizeof(chunks_to_process)/5); + /* These byte strings were copied from png.h. If a future libpng + * version recognizes more chunks, add them to this list. If a + * future version of readpng2.c recognizes more chunks, delete them + * from this list. */ + static /* const */ png_byte chunks_to_ignore[] = { + 99, 72, 82, 77, '\0', /* cHRM */ + 104, 73, 83, 84, '\0', /* hIST */ + 105, 67, 67, 80, '\0', /* iCCP */ + 105, 84, 88, 116, '\0', /* iTXt */ + 111, 70, 70, 115, '\0', /* oFFs */ + 112, 67, 65, 76, '\0', /* pCAL */ + 112, 72, 89, 115, '\0', /* pHYs */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 67, 65, 76, '\0', /* sCAL */ + 115, 80, 76, 84, '\0', /* sPLT */ + 115, 84, 69, 82, '\0', /* sTER */ + 116, 69, 88, 116, '\0', /* tEXt */ + 116, 73, 77, 69, '\0', /* tIME */ + 122, 84, 88, 116, '\0' /* zTXt */ + }; + + png_set_keep_unknown_chunks(png_ptr, 1 /* PNG_HANDLE_CHUNK_NEVER */, + chunks_to_ignore, sizeof(chunks_to_ignore)/5); } #endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */ diff --git a/contrib/libtests/fakepng.c b/contrib/libtests/fakepng.c deleted file mode 100644 index ba360d15a..000000000 --- a/contrib/libtests/fakepng.c +++ /dev/null @@ -1,57 +0,0 @@ -/* Fake a PNG - just write it out directly. */ -#include <stdio.h> -#include <zlib.h> /* for crc32 */ - -void -put_uLong(uLong val) -{ - putchar(val >> 24); - putchar(val >> 16); - putchar(val >> 8); - putchar(val >> 0); -} - -void -put_chunk(const unsigned char *chunk, uInt length) -{ - uLong crc; - - put_uLong(length-4); /* Exclude the tag */ - - fwrite(chunk, length, 1, stdout); - - crc = crc32(0, Z_NULL, 0); - put_uLong(crc32(crc, chunk, length)); -} - -const unsigned char signature[] = -{ - 137, 80, 78, 71, 13, 10, 26, 10 -}; - -const unsigned char IHDR[] = -{ - 73, 72, 68, 82, /* IHDR */ - 0, 0, 0, 1, /* width */ - 0, 0, 0, 1, /* height */ - 1, /* bit depth */ - 0, /* color type: greyscale */ - 0, /* compression method */ - 0, /* filter method */ - 0 /* interlace method: none */ -}; - -const unsigned char unknown[] = -{ - 'u', 'n', 'K', 'n' /* "unKn" - private safe to copy */ -}; - -int -main(void) -{ - fwrite(signature, sizeof signature, 1, stdout); - put_chunk(IHDR, sizeof IHDR); - - for(;;) - put_chunk(unknown, sizeof unknown); -} diff --git a/contrib/libtests/gentests.sh b/contrib/libtests/gentests.sh deleted file mode 100755 index f0f8d2395..000000000 --- a/contrib/libtests/gentests.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2013 John Cunningham Bowler -# -# Last changed in libpng 1.6.0 [February 14, 2013] -# -# This code is released under the libpng license. -# For conditions of distribution and use, see the disclaimer -# and license in png.h -# -# Generate a set of PNG test images. The images are generated in a -# sub-directory called 'tests' by default, however a command line argument will -# change that name. The generation requires a built version of makepng in the -# current directory. -# -usage(){ - exec >&2 - echo "$0 [<directory>]" - echo ' Generate a set of PNG test files in "directory" ("tests" by default)' - exit 1 -} - -mp="$PWD/makepng" -test -x "$mp" || { - exec >&2 - echo "$0: the 'makepng' program must exist" - echo " in the directory within which this program:" - echo " $mp" - echo " is executed" - usage -} - -# Just one argument: the directory -testdir="tests" -test $# -gt 1 && { - testdir="$1" - shift -} -test $# -eq 0 || usage - -# Take care not to clobber something -if test -e "$testdir" -then - test -d "$testdir" || usage -else - # mkdir -p isn't portable, so do the following - mkdir "$testdir" 2>/dev/null || mkdir -p "$testdir" || usage -fi - -# This fails in a very satisfactory way if it's not accessible -cd "$testdir" -:>"test$$.png" || { - exec >&2 - echo "$testdir: directory not writable" - usage -} -rm "test$$.png" || { - exec >&2 - echo "$testdir: you have create but not write privileges here." - echo " This is unexpected. You have a spurion; "'"'"test$$.png"'"'"." - echo " You need to remove this yourself. Try a different directory." - exit 1 -} - -# Now call makepng ($mp) to create every file we can think of with a -# reasonable name -doit(){ - for gamma in "" --sRGB --linear --1.8 - do - case "$gamma" in - "") - gname=;; - --sRGB) - gname="-srgb";; - --linear) - gname="-lin";; - --1.8) - gname="-18";; - *) - gname="-$gamma";; - esac - "$mp" $gamma "$1" "$2" "test-$1-$2$gname.png" - done -} -# -for ct in gray palette -do - for bd in 1 2 4 8 - do - doit "$ct" "$bd" - done -done -# -doit "gray" "16" -# -for ct in gray-alpha rgb rgb-alpha -do - for bd in 8 16 - do - doit "$ct" "$bd" - done -done diff --git a/contrib/libtests/makepng.c b/contrib/libtests/makepng.c deleted file mode 100644 index f5fdf5fd5..000000000 --- a/contrib/libtests/makepng.c +++ /dev/null @@ -1,1486 +0,0 @@ -/* makepng.c - * - * Copyright (c) 2013 John Cunningham Bowler - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * Make a test PNG image. The arguments are as follows: - * - * makepng [--sRGB|--linear|--1.8] [--color=<color>] color-type bit-depth \ - * [file-name] - * - * The color-type may be numeric (and must match the numbers used by the PNG - * specification) or one of the format names listed below. The bit-depth is the - * component bit depth, or the pixel bit-depth for a color-mapped image. - * - * Without any options no color-space information is written, with the options - * an sRGB or the appropriate gAMA chunk is written. "1.8" refers to the - * display system used on older Apple computers to correct for high ambient - * light levels in the viewing environment; it applies a transform of - * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909 - * is written (1.45/2.2). - * - * The image data is generated internally. Unless --color is given the images - * used are as follows: - * - * 1 channel: a square image with a diamond, the least luminous colors are on - * the edge of the image, the most luminous in the center. - * - * 2 channels: the color channel increases in luminosity from top to bottom, the - * alpha channel increases in opacity from left to right. - * - * 3 channels: linear combinations of, from the top-left corner clockwise, - * black, green, white, red. - * - * 4 channels: linear combinations of, from the top-left corner clockwise, - * transparent, red, green, blue. - * - * For color-mapped images a four channel color-map is used and the PNG file has - * a tRNS chunk, as follows: - * - * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white - * 2-bit: entry 0: transparent-green - * entry 1: 40%-red - * entry 2: 80%-blue - * entry 3: opaque-white - * 4-bit: the 16 combinations of the 2-bit case - * 8-bit: the 256 combinations of the 4-bit case - * - * The palette always has 2^bit-depth entries and the tRNS chunk one fewer. The - * image is the 1-channel diamond, but using palette index, not luminosity. - * - * Image size is determined by the final pixel depth in bits, i.e. channels x - * bit-depth, as follows: - * - * 8 bits or less: 64x64 - * 16 bits: 256x256 - * More than 16 bits: 1024x1024 - * - * Row filtering is turned off (the 'none' filter is used on every row) and the - * images are not interlaced. - * - * If --color is given then the whole image has that color, color-mapped images - * will have exactly one palette entry and all image files with be 16x16 in - * size. The color value is 1 to 4 decimal numbers as appropriate for the color - * type. - * - * If file-name is given then the PNG is written to that file, else it is - * written to stdout. Notice that stdout is not supported on systems where, by - * default, it assumes text output; this program makes no attempt to change the - * text mode of stdout! - */ -#define _ISOC99_SOURCE /* for strtoull */ - -#include <stddef.h> /* for offsetof */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <math.h> -#include <errno.h> - -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) -# include <config.h> -#endif - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include <png.h> -#else -# include "../../png.h" -#endif - -/* This structure is used for inserting extra chunks (the --insert argument, not - * documented above.) - */ -typedef struct chunk_insert -{ - struct chunk_insert *next; - void (*insert)(png_structp, png_infop, int, png_charpp); - int nparams; - png_charp parameters[1]; -} chunk_insert; - -static int -channels_of_type(int color_type) -{ - if (color_type & PNG_COLOR_MASK_PALETTE) - return 1; - - else - { - int channels = 1; - - if (color_type & PNG_COLOR_MASK_COLOR) - channels = 3; - - if (color_type & PNG_COLOR_MASK_ALPHA) - return channels + 1; - - else - return channels; - } -} - -static int -pixel_depth_of_type(int color_type, int bit_depth) -{ - return channels_of_type(color_type) * bit_depth; -} - -static unsigned int -image_size_of_type(int color_type, int bit_depth, unsigned int *colors) -{ - if (*colors) - return 16; - - else - { - int pixel_depth = pixel_depth_of_type(color_type, bit_depth); - - if (pixel_depth < 8) - return 64; - - else if (pixel_depth > 16) - return 1024; - - else - return 256; - } -} - -static void -set_color(png_colorp color, png_bytep trans, unsigned int red, - unsigned int green, unsigned int blue, unsigned int alpha, - png_const_bytep gamma_table) -{ - color->red = gamma_table[red]; - color->green = gamma_table[green]; - color->blue = gamma_table[blue]; - *trans = (png_byte)alpha; -} - -static int -generate_palette(png_colorp palette, png_bytep trans, int bit_depth, - png_const_bytep gamma_table, unsigned int *colors) -{ - /* - * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white - * 2-bit: entry 0: transparent-green - * entry 1: 40%-red - * entry 2: 80%-blue - * entry 3: opaque-white - * 4-bit: the 16 combinations of the 2-bit case - * 8-bit: the 256 combinations of the 4-bit case - */ - switch (colors[0]) - { - default: - fprintf(stderr, "makepng: --colors=...: invalid count %u\n", - colors[0]); - exit(1); - - case 1: - set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255, - gamma_table); - return 1; - - case 2: - set_color(palette+0, trans+0, colors[1], colors[1], colors[1], - colors[2], gamma_table); - return 1; - - case 3: - set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255, - gamma_table); - return 1; - - case 4: - set_color(palette+0, trans+0, colors[1], colors[2], colors[3], - colors[4], gamma_table); - return 1; - - case 0: - if (bit_depth == 1) - { - set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table); - set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table); - return 2; - } - - else - { - unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */ - unsigned int x, y, ip; - - for (x=0; x<size; ++x) for (y=0; y<size; ++y) - { - ip = x + (size * y); - - /* size is at most 16, so the scaled value below fits in 16 bits - */ -# define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2)) -# define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\ - (interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\ - (size*size)) - - set_color(palette+ip, trans+ip, - /* color: green, red,blue,white */ - xyinterp(x, y, 0, 255, 0, 255), - xyinterp(x, y, 255, 0, 0, 255), - xyinterp(x, y, 0, 0, 255, 255), - /* alpha: 0, 102, 204, 255) */ - xyinterp(x, y, 0, 102, 204, 255), - gamma_table); - } - - return ip+1; - } - } -} - -static void -set_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth, - png_uint_32 value, png_const_bytep gamma_table, double conv) -{ - unsigned int mask = (1U << bit_depth)-1; - - x *= bit_depth; /* Maximum x is 4*1024, maximum bit_depth is 16 */ - - if (value <= mask) - { - png_uint_32 offset = x >> 3; - - if (offset < rowbytes && (bit_depth < 16 || offset+1 < rowbytes)) - { - row += offset; - - switch (bit_depth) - { - case 1: - case 2: - case 4: - /* Don't gamma correct - values get smashed */ - { - unsigned int shift = (8 - bit_depth) - (x & 0x7U); - - mask <<= shift; - value = (value << shift) & mask; - *row = (png_byte)((*row & ~mask) | value); - } - return; - - default: - fprintf(stderr, "makepng: bad bit depth (internal error)\n"); - exit(1); - - case 16: - value = (unsigned int)floor(65535*pow(value/65535.,conv)+.5); - *row++ = (png_byte)(value >> 8); - *row = (png_byte)value; - return; - - case 8: - *row = gamma_table[value]; - return; - } - } - - else - { - fprintf(stderr, "makepng: row buffer overflow (internal error)\n"); - exit(1); - } - } - - else - { - fprintf(stderr, "makepng: component overflow (internal error)\n"); - exit(1); - } -} - -static void -generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type, - int bit_depth, png_const_bytep gamma_table, double conv, - unsigned int *colors) -{ - png_uint_32 size_max = image_size_of_type(color_type, bit_depth, colors)-1; - png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */ - - if (colors[0] == 0) switch (channels_of_type(color_type)) - { - /* 1 channel: a square image with a diamond, the least luminous colors are on - * the edge of the image, the most luminous in the center. - */ - case 1: - { - png_uint_32 x; - png_uint_32 base = 2*size_max - abs(2*y-size_max); - - for (x=0; x<=size_max; ++x) - { - png_uint_32 luma = base - abs(2*x-size_max); - - /* 'luma' is now in the range 0..2*size_max, we need - * 0..depth_max - */ - luma = (luma*depth_max + size_max) / (2*size_max); - set_value(row, rowbytes, x, bit_depth, luma, gamma_table, conv); - } - } - break; - - /* 2 channels: the color channel increases in luminosity from top to bottom, - * the alpha channel increases in opacity from left to right. - */ - case 2: - { - png_uint_32 alpha = (depth_max * y * 2 + size_max) / (2 * size_max); - png_uint_32 x; - - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 2*x, bit_depth, - (depth_max * x * 2 + size_max) / (2 * size_max), gamma_table, - conv); - set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table, - conv); - } - } - break; - - /* 3 channels: linear combinations of, from the top-left corner clockwise, - * black, green, white, red. - */ - case 3: - { - /* x0: the black->red scale (the value of the red component) at the - * start of the row (blue and green are 0). - * x1: the green->white scale (the value of the red and blue - * components at the end of the row; green is depth_max). - */ - png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); - png_uint_32 x; - - /* Interpolate x/depth_max from start to end: - * - * start end difference - * red: Y Y 0 - * green: 0 depth_max depth_max - * blue: 0 Y Y - */ - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 3*x+0, bit_depth, /* red */ Y, - gamma_table, conv); - set_value(row, rowbytes, 3*x+1, bit_depth, /* green */ - (depth_max * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 3*x+2, bit_depth, /* blue */ - (Y * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - } - } - break; - - /* 4 channels: linear combinations of, from the top-left corner clockwise, - * transparent, red, green, blue. - */ - case 4: - { - /* x0: the transparent->blue scale (the value of the blue and alpha - * components) at the start of the row (red and green are 0). - * x1: the red->green scale (the value of the red and green - * components at the end of the row; blue is 0 and alpha is - * depth_max). - */ - png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max); - png_uint_32 x; - - /* Interpolate x/depth_max from start to end: - * - * start end difference - * red: 0 depth_max-Y depth_max-Y - * green: 0 Y Y - * blue: Y 0 -Y - * alpha: Y depth_max depth_max-Y - */ - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 4*x+0, bit_depth, /* red */ - ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 4*x+1, bit_depth, /* green */ - (Y * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 4*x+2, bit_depth, /* blue */ - Y - (Y * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - set_value(row, rowbytes, 4*x+3, bit_depth, /* alpha */ - Y + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max), - gamma_table, conv); - } - } - break; - - default: - fprintf(stderr, "makepng: internal bad channel count\n"); - exit(2); - } - - else if (color_type & PNG_COLOR_MASK_PALETTE) - { - /* Palette with fixed color: the image rows are all 0 and the image width - * is 16. - */ - memset(row, rowbytes, 0); - } - - else if (colors[0] == channels_of_type(color_type)) - switch (channels_of_type(color_type)) - { - case 1: - { - const png_uint_32 luma = colors[1]; - png_uint_32 x; - - for (x=0; x<=size_max; ++x) - set_value(row, rowbytes, x, bit_depth, luma, gamma_table, - conv); - } - break; - - case 2: - { - const png_uint_32 luma = colors[1]; - const png_uint_32 alpha = colors[2]; - png_uint_32 x; - - for (x=0; x<size_max; ++x) - { - set_value(row, rowbytes, 2*x, bit_depth, luma, gamma_table, - conv); - set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table, - conv); - } - } - break; - - case 3: - { - const png_uint_32 red = colors[1]; - const png_uint_32 green = colors[2]; - const png_uint_32 blue = colors[3]; - png_uint_32 x; - - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 3*x+0, bit_depth, red, gamma_table, - conv); - set_value(row, rowbytes, 3*x+1, bit_depth, green, gamma_table, - conv); - set_value(row, rowbytes, 3*x+2, bit_depth, blue, gamma_table, - conv); - } - } - break; - - case 4: - { - const png_uint_32 red = colors[1]; - const png_uint_32 green = colors[2]; - const png_uint_32 blue = colors[3]; - const png_uint_32 alpha = colors[4]; - png_uint_32 x; - - for (x=0; x<=size_max; ++x) - { - set_value(row, rowbytes, 4*x+0, bit_depth, red, gamma_table, - conv); - set_value(row, rowbytes, 4*x+1, bit_depth, green, gamma_table, - conv); - set_value(row, rowbytes, 4*x+2, bit_depth, blue, gamma_table, - conv); - set_value(row, rowbytes, 4*x+3, bit_depth, alpha, gamma_table, - conv); - } - } - break; - - default: - fprintf(stderr, "makepng: internal bad channel count\n"); - exit(2); - } - - else - { - fprintf(stderr, - "makepng: --color: count(%u) does not match channels(%u)\n", - colors[0], channels_of_type(color_type)); - exit(1); - } -} - - -static void PNGCBAPI -makepng_warning(png_structp png_ptr, png_const_charp message) -{ - const char **ep = png_get_error_ptr(png_ptr); - const char *name; - - if (ep != NULL && *ep != NULL) - name = *ep; - - else - name = "makepng"; - - fprintf(stderr, "%s: warning: %s\n", name, message); -} - -static void PNGCBAPI -makepng_error(png_structp png_ptr, png_const_charp message) -{ - makepng_warning(png_ptr, message); - png_longjmp(png_ptr, 1); -} - -static int /* 0 on success, else an error code */ -write_png(const char **name, FILE *fp, int color_type, int bit_depth, - volatile png_fixed_point gamma, chunk_insert * volatile insert, - unsigned int filters, unsigned int *colors) -{ - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - name, makepng_error, makepng_warning); - volatile png_infop info_ptr = NULL; - volatile png_bytep row = NULL; - - if (png_ptr == NULL) - { - fprintf(stderr, "makepng: OOM allocating write structure\n"); - return 1; - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_structp nv_ptr = png_ptr; - png_infop nv_info = info_ptr; - - png_ptr = NULL; - info_ptr = NULL; - png_destroy_write_struct(&nv_ptr, &nv_info); - if (row != NULL) free(row); - return 1; - } - - /* Allow benign errors so that we can write PNGs with errors */ - png_set_benign_errors(png_ptr, 1/*allowed*/); - png_init_io(png_ptr, fp); - - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - png_error(png_ptr, "OOM allocating info structure"); - - { - unsigned int size = image_size_of_type(color_type, bit_depth, colors); - png_fixed_point real_gamma = 45455; /* For sRGB */ - png_byte gamma_table[256]; - double conv; - - /* This function uses the libpng values used on read to carry extra - * information about the gamma: - */ - if (gamma == PNG_GAMMA_MAC_18) - gamma = 65909; - - else if (gamma > 0 && gamma < 1000) - gamma = PNG_FP_1; - - if (gamma > 0) - real_gamma = gamma; - - { - unsigned int i; - - if (real_gamma == 45455) for (i=0; i<256; ++i) - { - gamma_table[i] = (png_byte)i; - conv = 1.; - } - - else - { - /* Convert 'i' from sRGB (45455) to real_gamma, this makes - * the images look the same regardless of the gAMA chunk. - */ - conv = real_gamma; - conv /= 45455; - - gamma_table[0] = 0; - - for (i=0; i<255; ++i) - gamma_table[i] = (png_byte)floor(pow(i/255.,conv) * 255 + 127.5); - - gamma_table[255] = 255; - } - } - - png_set_IHDR(png_ptr, info_ptr, size, size, bit_depth, color_type, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - if (color_type & PNG_COLOR_MASK_PALETTE) - { - int npalette; - png_color palette[256]; - png_byte trans[256]; - - npalette = generate_palette(palette, trans, bit_depth, gamma_table, - colors); - png_set_PLTE(png_ptr, info_ptr, palette, npalette); - png_set_tRNS(png_ptr, info_ptr, trans, npalette-1, - NULL/*transparent color*/); - - /* Reset gamma_table to prevent the image rows being changed */ - for (npalette=0; npalette<256; ++npalette) - gamma_table[npalette] = (png_byte)npalette; - } - - if (gamma == PNG_DEFAULT_sRGB) - png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); - - else if (gamma > 0) /* Else don't set color space information */ - { - png_set_gAMA_fixed(png_ptr, info_ptr, real_gamma); - - /* Just use the sRGB values here. */ - png_set_cHRM_fixed(png_ptr, info_ptr, - /* color x y */ - /* white */ 31270, 32900, - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000 - ); - } - - /* Insert extra information. */ - while (insert != NULL) - { - insert->insert(png_ptr, info_ptr, insert->nparams, insert->parameters); - insert = insert->next; - } - - /* Write the file header. */ - png_write_info(png_ptr, info_ptr); - - /* Restrict the filters */ - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters); - - { - int passes = png_set_interlace_handling(png_ptr); - int pass; - png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); - - row = malloc(rowbytes); - - if (row == NULL) - png_error(png_ptr, "OOM allocating row buffer"); - - for (pass = 0; pass < passes; ++pass) - { - unsigned int y; - - for (y=0; y<size; ++y) - { - generate_row(row, rowbytes, y, color_type, bit_depth, - gamma_table, conv, colors); - png_write_row(png_ptr, row); - } - } - } - } - - /* Finish writing the file. */ - png_write_end(png_ptr, info_ptr); - - { - png_structp nv_ptr = png_ptr; - png_infop nv_info = info_ptr; - - png_ptr = NULL; - info_ptr = NULL; - png_destroy_write_struct(&nv_ptr, &nv_info); - } - free(row); - return 0; -} - - -static size_t -load_file(png_const_charp name, png_bytepp result) -{ - FILE *fp = tmpfile(); - - if (fp != NULL) - { - FILE *ip = fopen(name, "rb"); - - if (ip != NULL) - { - size_t total = 0; - int ch; - - for (;;) - { - ch = getc(ip); - if (ch == EOF) break; - putc(ch, fp); - ++total; - } - - if (ferror(ip)) - { - perror(name); - fprintf(stderr, "%s: read error\n", name); - (void)fclose(ip); - } - - else - { - (void)fclose(ip); - - if (ferror(fp)) - { - perror("temporary file"); - fprintf(stderr, "temporary file write error\n"); - } - - else - { - rewind(fp); - - if (total > 0) - { - /* Round up to a multiple of 4 here to allow an iCCP profile - * to be padded to a 4x boundary. - */ - png_bytep data = malloc((total+3)&~3); - - if (data != NULL) - { - size_t new_size = 0; - - for (;;) - { - ch = getc(fp); - if (ch == EOF) break; - data[new_size++] = (png_byte)ch; - } - - if (ferror(fp) || new_size != total) - { - perror("temporary file"); - fprintf(stderr, "temporary file read error\n"); - free(data); - } - - else - { - (void)fclose(fp); - *result = data; - return total; - } - } - - else - fprintf(stderr, "%s: out of memory loading file\n", name); - } - - else - fprintf(stderr, "%s: empty file\n", name); - } - } - } - - else - { - perror(name); - fprintf(stderr, "%s: open failed\n", name); - } - - fclose(fp); - } - - else - fprintf(stderr, "makepng: %s: could not open temporary file\n", name); - - exit(1); - return 0; -} - -static png_size_t -load_fake(png_charp param, png_bytepp profile) -{ - char *endptr = NULL; - unsigned long long int size = strtoull(param, &endptr, 0/*base*/); - - /* The 'fake' format is <number>*[string] */ - if (endptr != NULL && *endptr == '*') - { - size_t len = strlen(++endptr); - size_t result = (size_t)size; - - if (len == 0) len = 1; /* capture the terminating '\0' */ - - /* Now repeat that string to fill 'size' bytes. */ - if (result == size && (*profile = malloc(result)) != NULL) - { - png_bytep out = *profile; - - if (len == 1) - memset(out, *endptr, result); - - else - { - while (size >= len) - { - memcpy(out, endptr, len); - out += len; - size -= len; - } - memcpy(out, endptr, size); - } - - return result; - } - - else - { - fprintf(stderr, "%s: size exceeds system limits\n", param); - exit(1); - } - } - - return 0; -} - -static void -check_param_count(int nparams, int expect) -{ - if (nparams != expect) - { - fprintf(stderr, "bad parameter count (internal error)\n"); - exit(1); - } -} - -static void -insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_bytep profile = NULL; - png_uint_32 proflen = 0; - int result; - - check_param_count(nparams, 2); - - switch (params[1][0]) - { - case '<': - { - png_size_t filelen = load_file(params[1]+1, &profile); - if (filelen > 0xfffffffc) /* Maximum profile length */ - { - fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n", - params[1]+1, (unsigned long)filelen); - exit(1); - } - - proflen = (png_uint_32)filelen; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - png_size_t fake_len = load_fake(params[1], &profile); - - if (fake_len > 0) /* else a simple parameter */ - { - if (fake_len > 0xffffffff) /* Maximum profile length */ - { - fprintf(stderr, - "%s: fake data too long (%lu) for an ICC profile\n", - params[1], (unsigned long)fake_len); - exit(1); - } - proflen = (png_uint_32)(fake_len & ~3U); - /* Always fix up the profile length. */ - png_save_uint_32(profile, proflen); - break; - } - } - - default: - fprintf(stderr, "--insert iCCP \"%s\": unrecognized\n", params[1]); - fprintf(stderr, " use '<' to read a file: \"<filename\"\n"); - exit(1); - } - - result = 1; - - if (proflen & 3) - { - fprintf(stderr, - "makepng: --insert iCCP %s: profile length made a multiple of 4\n", - params[1]); - - /* load_file allocates extra space for this padding, the ICC spec requires - * padding with zero bytes. - */ - while (proflen & 3) - profile[proflen++] = 0; - } - - if (profile != NULL && proflen > 3) - { - png_uint_32 prof_header = png_get_uint_32(profile); - - if (prof_header != proflen) - { - fprintf(stderr, "--insert iCCP %s: profile length field wrong:\n", - params[1]); - fprintf(stderr, " actual %lu, recorded value %lu (corrected)\n", - (unsigned long)proflen, (unsigned long)prof_header); - png_save_uint_32(profile, proflen); - } - } - - if (result && profile != NULL && proflen >=4) - png_set_iCCP(png_ptr, info_ptr, params[0], PNG_COMPRESSION_TYPE_BASE, - profile, proflen); - - if (profile) - free(profile); - - if (!result) - exit(1); -} - -static void -clear_text(png_text *text, png_charp keyword) -{ - text->compression = -1; /* none */ - text->key = keyword; - text->text = NULL; - text->text_length = 0; /* libpng calculates this */ - text->itxt_length = 0; /* libpng calculates this */ - text->lang = NULL; - text->lang_key = NULL; -} - -static void -set_text(png_structp png_ptr, png_infop info_ptr, png_textp text, - png_charp param) -{ - switch (param[0]) - { - case '<': - { - png_bytep file = NULL; - - text->text_length = load_file(param+1, &file); - text->text = (png_charp)file; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - png_bytep data = NULL; - png_size_t fake_len = load_fake(param, &data); - - if (fake_len > 0) /* else a simple parameter */ - { - text->text_length = fake_len; - text->text = (png_charp)data; - break; - } - } - - default: - text->text = param; - break; - } - - png_set_text(png_ptr, info_ptr, text, 1); - - if (text->text != param) - free(text->text); -} - -static void -insert_tEXt(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_text text; - - check_param_count(nparams, 2); - clear_text(&text, params[0]); - set_text(png_ptr, info_ptr, &text, params[1]); -} - -static void -insert_zTXt(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_text text; - - check_param_count(nparams, 2); - clear_text(&text, params[0]); - text.compression = 0; /* deflate */ - set_text(png_ptr, info_ptr, &text, params[1]); -} - -static void -insert_iTXt(png_structp png_ptr, png_infop info_ptr, int nparams, - png_charpp params) -{ - png_text text; - - check_param_count(nparams, 4); - clear_text(&text, params[0]); - text.compression = 2; /* iTXt + deflate */ - text.lang = params[1];/* language tag */ - text.lang_key = params[2]; /* translated keyword */ - set_text(png_ptr, info_ptr, &text, params[3]); -} - -static void -insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params) -{ - int i; - png_uint_16 freq[256]; - - /* libpng takes the count from the PLTE count; we don't check it here but we - * do set the array to 0 for unspecified entries. - */ - memset(freq, 0, sizeof freq); - for (i=0; i<nparams; ++i) - { - char *endptr = NULL; - unsigned long int l = strtoul(params[i], &endptr, 0/*base*/); - - if (params[i][0] && *endptr == 0 && l <= 65535) - freq[i] = (png_uint_16)l; - - else - { - fprintf(stderr, "hIST[%d]: %s: invalid frequency\n", i, params[i]); - exit(1); - } - } - - png_set_hIST(png_ptr, info_ptr, freq); -} - -#if 0 -static void -insert_sPLT(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params) -{ - fprintf(stderr, "insert sPLT: NYI\n"); -} -#endif - -static int -find_parameters(png_const_charp what, png_charp param, png_charp *list, - int nparams) -{ - /* Parameters are separated by '\n' or ':' characters, up to nparams are - * accepted (more is an error) and the number found is returned. - */ - int i; - for (i=0; *param && i<nparams; ++i) - { - list[i] = param; - while (*++param) if (*param == '\n' || *param == ':') - { - *param++ = 0; /* Terminate last parameter */ - break; /* And start a new one. */ - } - } - - if (*param) - { - fprintf(stderr, "--insert %s: too many parameters (%s)\n", what, param); - exit(1); - } - - list[i] = NULL; /* terminates list */ - return i; /* number of parameters filled in */ -} - -static void -bad_parameter_count(png_const_charp what, int nparams) -{ - fprintf(stderr, "--insert %s: bad parameter count %d\n", what, nparams); - exit(1); -} - -static chunk_insert * -make_insert(png_const_charp what, - void (*insert)(png_structp, png_infop, int, png_charpp), - int nparams, png_charpp list) -{ - int i; - chunk_insert *cip; - - cip = malloc(offsetof(chunk_insert,parameters) + - nparams * sizeof (png_charp)); - - if (cip == NULL) - { - fprintf(stderr, "--insert %s: out of memory allocating %d parameters\n", - what, nparams); - exit(1); - } - - cip->next = NULL; - cip->insert = insert; - cip->nparams = nparams; - for (i=0; i<nparams; ++i) - cip->parameters[i] = list[i]; - - return cip; -} - -static chunk_insert * -find_insert(png_const_charp what, png_charp param) -{ - png_uint_32 chunk = 0; - png_charp parameter_list[1024]; - int i, nparams; - - /* Assemble the chunk name */ - for (i=0; i<4; ++i) - { - char ch = what[i]; - - if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) - chunk = (chunk << 8) + what[i]; - - else - break; - } - - if (i < 4 || what[4] != 0) - { - fprintf(stderr, "makepng --insert \"%s\": invalid chunk name\n", what); - exit(1); - } - - /* Assemble the parameter list. */ - nparams = find_parameters(what, param, parameter_list, 1024); - -# define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) - - switch (chunk) - { - case CHUNK(105,67,67,80): /* iCCP */ - if (nparams == 2) - return make_insert(what, insert_iCCP, nparams, parameter_list); - break; - - case CHUNK(116,69,88,116): /* tEXt */ - if (nparams == 2) - return make_insert(what, insert_tEXt, nparams, parameter_list); - break; - - case CHUNK(122,84,88,116): /* zTXt */ - if (nparams == 2) - return make_insert(what, insert_zTXt, nparams, parameter_list); - break; - - case CHUNK(105,84,88,116): /* iTXt */ - if (nparams == 4) - return make_insert(what, insert_iTXt, nparams, parameter_list); - break; - - case CHUNK(104,73,83,84): /* hIST */ - if (nparams <= 256) - return make_insert(what, insert_hIST, nparams, parameter_list); - break; - -#if 0 - case CHUNK(115,80,76,84): /* sPLT */ - return make_insert(what, insert_sPLT, nparams, parameter_list); -#endif - - default: - fprintf(stderr, "makepng --insert \"%s\": unrecognized chunk name\n", - what); - exit(1); - } - - bad_parameter_count(what, nparams); - return NULL; -} - -/* This is a not-very-good parser for a sequence of numbers (including 0). It - * doesn't accept some apparently valid things, but it accepts all the sensible - * combinations. - */ -static void -parse_color(char *arg, unsigned int *colors) -{ - unsigned int ncolors = 0; - - while (*arg && ncolors < 4) - { - char *ep = arg; - - unsigned long ul = strtoul(arg, &ep, 0); - - if (ul > 65535) - { - fprintf(stderr, "makepng --color=...'%s': too big\n", arg); - exit(1); - } - - if (ep == arg) - { - fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg); - exit(1); - } - - if (*ep) ++ep; /* skip a separator */ - arg = ep; - - colors[++ncolors] = (unsigned int)ul; /* checked above */ - } - - if (*arg) - { - fprintf(stderr, "makepng --color=...'%s': too many values\n", arg); - exit(1); - } - - *colors = ncolors; -} - -int -main(int argc, char **argv) -{ - FILE *fp = stdout; - const char *file_name = NULL; - int color_type = 8; /* invalid */ - int bit_depth = 32; /* invalid */ - unsigned int colors[5]; - unsigned int filters = PNG_ALL_FILTERS; - png_fixed_point gamma = 0; /* not set */ - chunk_insert *head_insert = NULL; - chunk_insert **insert_ptr = &head_insert; - - memset(colors, 0, sizeof colors); - - while (--argc > 0) - { - char *arg = *++argv; - - if (strcmp(arg, "--sRGB") == 0) - { - gamma = PNG_DEFAULT_sRGB; - continue; - } - - if (strcmp(arg, "--linear") == 0) - { - gamma = PNG_FP_1; - continue; - } - - if (strcmp(arg, "--1.8") == 0) - { - gamma = PNG_GAMMA_MAC_18; - continue; - } - - if (strcmp(arg, "--nofilters") == 0) - { - filters = PNG_FILTER_NONE; - continue; - } - - if (strncmp(arg, "--color=", 8) == 0) - { - parse_color(arg+8, colors); - continue; - } - - if (argc >= 3 && strcmp(arg, "--insert") == 0) - { - png_const_charp what = *++argv; - png_charp param = *++argv; - chunk_insert *new_insert; - - argc -= 2; - - new_insert = find_insert(what, param); - - if (new_insert != NULL) - { - *insert_ptr = new_insert; - insert_ptr = &new_insert->next; - } - - continue; - } - - if (arg[0] == '-') - { - fprintf(stderr, "makepng: %s: invalid option\n", arg); - exit(1); - } - - if (strcmp(arg, "palette") == 0) - { - color_type = PNG_COLOR_TYPE_PALETTE; - continue; - } - - if (strncmp(arg, "gray", 4) == 0) - { - if (arg[4] == 0) - { - color_type = PNG_COLOR_TYPE_GRAY; - continue; - } - - else if (strcmp(arg+4, "a") == 0 || - strcmp(arg+4, "alpha") == 0 || - strcmp(arg+4, "-alpha") == 0) - { - color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - continue; - } - } - - if (strncmp(arg, "rgb", 3) == 0) - { - if (arg[3] == 0) - { - color_type = PNG_COLOR_TYPE_RGB; - continue; - } - - else if (strcmp(arg+3, "a") == 0 || - strcmp(arg+3, "alpha") == 0 || - strcmp(arg+3, "-alpha") == 0) - { - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - continue; - } - } - - if (color_type == 8 && isdigit(arg[0])) - { - color_type = atoi(arg); - if (color_type < 0 || color_type > 6 || color_type == 1 || - color_type == 5) - { - fprintf(stderr, "makepng: %s: not a valid color type\n", arg); - exit(1); - } - - continue; - } - - if (bit_depth == 32 && isdigit(arg[0])) - { - bit_depth = atoi(arg); - if (bit_depth <= 0 || bit_depth > 16 || - (bit_depth & -bit_depth) != bit_depth) - { - fprintf(stderr, "makepng: %s: not a valid bit depth\n", arg); - exit(1); - } - - continue; - } - - if (argc == 1) /* It's the file name */ - { - fp = fopen(arg, "wb"); - if (fp == NULL) - { - fprintf(stderr, "%s: %s: could not open\n", arg, strerror(errno)); - exit(1); - } - - file_name = arg; - continue; - } - - fprintf(stderr, "makepng: %s: unknown argument\n", arg); - exit(1); - } /* argument while loop */ - - if (color_type == 8 || bit_depth == 32) - { - fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] " - "[--color=...] color-type bit-depth [file-name]\n" - " Make a test PNG file, by default writes to stdout.\n"); - exit(1); - } - - /* Check the colors */ - { - const unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U : - (1U<<bit_depth)-1); - unsigned int i; - - for (i=1; i<=colors[0]; ++i) - if (colors[i] > lim) - { - fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n", - colors[i], lim); - exit(1); - } - } - - /* Restrict the filters for more speed to those we know are used for the - * generated images. - */ - if (filters == PNG_ALL_FILTERS) - { - if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8) - filters = PNG_FILTER_NONE; - - else if (color_type & PNG_COLOR_MASK_COLOR) /* rgb */ - { - if (bit_depth == 8) - filters &= ~(PNG_FILTER_NONE | PNG_FILTER_AVG); - - else - filters = PNG_FILTER_SUB | PNG_FILTER_PAETH; - } - - else /* gray 8 or 16-bit */ - filters &= ~PNG_FILTER_NONE; - } - - { - int ret = write_png(&file_name, fp, color_type, bit_depth, gamma, - head_insert, filters, colors); - - if (ret != 0 && file_name != NULL) - remove(file_name); - - return ret; - } -} diff --git a/contrib/libtests/pngstest.c b/contrib/libtests/pngstest.c index 32d5eea49..6e17b2022 100644 --- a/contrib/libtests/pngstest.c +++ b/contrib/libtests/pngstest.c @@ -1,9 +1,9 @@ /*- * pngstest.c * - * Copyright (c) 2013 John Cunningham Bowler + * Copyright (c) 2012 John Cunningham Bowler * - * Last changed in libpng 1.6.0 [February 14, 2013] + * Last changed in libpng 1.6.0 [(PENDING RELEASE)] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -22,7 +22,7 @@ #include <ctype.h> #include <math.h> -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +#if (defined HAVE_CONFIG_H) && !(defined PNG_NO_CONFIG_H) # include <config.h> #endif @@ -35,77 +35,15 @@ # include "../../png.h" #endif -#ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* Else nothing can be done */ #include "../tools/sRGB.h" -/* KNOWN ISSUES - * - * These defines switch on alternate algorithms for format conversions to match - * the current libpng implementation; they are set to allow pngstest to pass - * even though libpng is producing answers that are not as correct as they - * should be. - */ -#define ALLOW_UNUSED_GPC 0 - /* If true include unused static GPC functions and declare an external array - * of them to hide the fact that they are unused. This is for development - * use while testing the correct function to use to take into account libpng - * misbehavior, such as using a simple power law to correct sRGB to linear. - */ - /* The following is to support direct compilation of this file as C++ */ #ifdef __cplusplus # define voidcast(type, value) static_cast<type>(value) -# define aligncastconst(type, value) \ - static_cast<type>(static_cast<const void*>(value)) #else # define voidcast(type, value) (value) -# define aligncastconst(type, value) ((const void*)(value)) #endif /* __cplusplus */ -/* During parallel runs of pngstest each temporary file needs a unique name, - * this is used to permit uniqueness using a command line argument which can be - * up to 22 characters long. - */ -static char tmpf[23] = "TMP"; - -/* Generate random bytes. This uses a boring repeatable algorithm and it - * is implemented here so that it gives the same set of numbers on every - * architecture. It's a linear congruential generator (Knuth or Sedgewick - * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and - * Hill, "The Art of Electronics". - */ -static void -make_random_bytes(png_uint_32* seed, void* pv, size_t size) -{ - png_uint_32 u0 = seed[0], u1 = seed[1]; - png_bytep bytes = voidcast(png_bytep, pv); - - /* There are thirty three bits, the next bit in the sequence is bit-33 XOR - * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. - */ - size_t i; - for (i=0; i<size; ++i) - { - /* First generate 8 new bits then shift them in at the end. */ - png_uint_32 u = ((u0 >> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; - u1 <<= 8; - u1 |= u0 >> 24; - u0 <<= 8; - u0 |= u; - *bytes++ = (png_byte)u; - } - - seed[0] = u0; - seed[1] = u1; -} - -static void -random_color(png_colorp color) -{ - static png_uint_32 color_seed[2] = { 0x12345678, 0x9abcdef }; - make_random_bytes(color_seed, color, sizeof *color); -} - /* Math support - neither Cygwin nor Visual Studio have C99 support and we need * a predictable rounding function, so make one here: */ @@ -131,27 +69,8 @@ u16d(double d) } /* sRGB support: use exact calculations rounded to the nearest int, see the - * fesetround() call in main(). sRGB_to_d optimizes the 8 to 16-bit conversion. + * fesetround() call in main(). */ -static double sRGB_to_d[256]; -static double g22_to_d[256]; - -static void -init_sRGB_to_d(void) -{ - int i; - - sRGB_to_d[0] = 0; - for (i=1; i<255; ++i) - sRGB_to_d[i] = linear_from_sRGB(i/255.); - sRGB_to_d[255] = 1; - - g22_to_d[0] = 0; - for (i=1; i<255; ++i) - g22_to_d[i] = pow(i/255., 1/.45455); - g22_to_d[255] = 1; -} - static png_byte sRGB(double linear /*range 0.0 .. 1.0*/) { @@ -164,47 +83,12 @@ isRGB(int fixed_linear) return sRGB(fixed_linear / 65535.); } -#if 0 /* not used */ -static png_byte -unpremultiply(int component, int alpha) -{ - if (alpha <= component) - return 255; /* Arbitrary, but consistent with the libpng code */ - - else if (alpha >= 65535) - return isRGB(component); - - else - return sRGB((double)component / alpha); -} -#endif - -static png_uint_16 -ilinear(int fixed_srgb) -{ - return u16d(65535 * sRGB_to_d[fixed_srgb]); -} - static png_uint_16 ilineara(int fixed_srgb, int alpha) { - return u16d((257 * alpha) * sRGB_to_d[fixed_srgb]); -} - -static png_uint_16 -ilinear_g22(int fixed_srgb) -{ - return u16d(65535 * g22_to_d[fixed_srgb]); + return u16d((257 * alpha) * linear_from_sRGB(fixed_srgb / 255.)); } -#if ALLOW_UNUSED_GPC -static png_uint_16 -ilineara_g22(int fixed_srgb, int alpha) -{ - return u16d((257 * alpha) * g22_to_d[fixed_srgb]); -} -#endif - static double YfromRGBint(int ir, int ig, int ib) { @@ -214,107 +98,12 @@ YfromRGBint(int ir, int ig, int ib) return YfromRGB(r, g, b); } -#if 0 /* unused */ -/* The error that results from using a 2.2 power law in place of the correct - * sRGB transform, given an 8-bit value which might be either sRGB or power-law. - */ -static int -power_law_error8(int value) -{ - if (value > 0 && value < 255) - { - double vd = value / 255.; - double e = fabs( - pow(sRGB_to_d[value], 1/2.2) - sRGB_from_linear(pow(vd, 2.2))); - - /* Always allow an extra 1 here for rounding errors */ - e = 1+floor(255 * e); - return (int)e; - } - - return 0; -} - -static int error_in_sRGB_roundtrip = 56; /* by experiment */ -static int -power_law_error16(int value) -{ - if (value > 0 && value < 65535) - { - /* Round trip the value through an 8-bit representation but using - * non-matching to/from conversions. - */ - double vd = value / 65535.; - double e = fabs( - pow(sRGB_from_linear(vd), 2.2) - linear_from_sRGB(pow(vd, 1/2.2))); - - /* Always allow an extra 1 here for rounding errors */ - e = error_in_sRGB_roundtrip+floor(65535 * e); - return (int)e; - } - - return 0; -} - -static int -compare_8bit(int v1, int v2, int error_limit, int multiple_algorithms) -{ - int e = abs(v1-v2); - int ev1, ev2; - - if (e <= error_limit) - return 1; - - if (!multiple_algorithms) - return 0; - - ev1 = power_law_error8(v1); - if (e <= ev1) - return 1; - - ev2 = power_law_error8(v2); - if (e <= ev2) - return 1; - - return 0; -} - -static int -compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) -{ - int e = abs(v1-v2); - int ev1, ev2; - - if (e <= error_limit) - return 1; - - /* "multiple_algorithms" in this case means that a color-map has been - * involved somewhere, so we can deduce that the values were forced to 8-bit - * (like the via_linear case for 8-bit.) - */ - if (!multiple_algorithms) - return 0; - - ev1 = power_law_error16(v1); - if (e <= ev1) - return 1; - - ev2 = power_law_error16(v2); - if (e <= ev2) - return 1; - - return 0; -} -#endif /* unused */ - #define READ_FILE 1 /* else memory */ #define USE_STDIO 2 /* else use file name */ -#define STRICT 4 /* fail on warnings too */ +#define USE_BACKGROUND 4 /* else composite in place */ #define VERBOSE 8 #define KEEP_TMPFILES 16 /* else delete temporary files */ #define KEEP_GOING 32 -#define ACCUMULATE 64 -#define FAST_WRITE 128 static void print_opts(png_uint_32 opts) @@ -323,18 +112,14 @@ print_opts(png_uint_32 opts) printf(" --file"); if (opts & USE_STDIO) printf(" --stdio"); - if (opts & STRICT) - printf(" --strict"); + if (opts & USE_BACKGROUND) + printf(" --background"); if (opts & VERBOSE) printf(" --verbose"); if (opts & KEEP_TMPFILES) printf(" --preserve"); if (opts & KEEP_GOING) printf(" --keep-going"); - if (opts & ACCUMULATE) - printf(" --accumulate"); - if (!(opts & FAST_WRITE)) /* --fast is currently the default */ - printf(" --slow"); } #define FORMAT_NO_CHANGE 0x80000000 /* additional flag */ @@ -342,9 +127,7 @@ print_opts(png_uint_32 opts) /* A name table for all the formats - defines the format of the '+' arguments to * pngstest. */ -#define FORMAT_COUNT 64 -#define FORMAT_MASK 0x3f -static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = +static PNG_CONST char * PNG_CONST format_names[32] = { "sRGB-gray", "sRGB-gray+alpha", @@ -354,16 +137,6 @@ static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = "linear-gray+alpha", "linear-rgb", "linear-rgb+alpha", - - "color-mapped-sRGB-gray", - "color-mapped-sRGB-gray+alpha", - "color-mapped-sRGB-rgb", - "color-mapped-sRGB-rgb+alpha", - "color-mapped-linear-gray", - "color-mapped-linear-gray+alpha", - "color-mapped-linear-rgb", - "color-mapped-linear-rgb+alpha", - "sRGB-gray", "sRGB-gray+alpha", "sRGB-bgr", @@ -372,16 +145,6 @@ static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = "linear-gray+alpha", "linear-bgr", "linear-bgr+alpha", - - "color-mapped-sRGB-gray", - "color-mapped-sRGB-gray+alpha", - "color-mapped-sRGB-bgr", - "color-mapped-sRGB-bgr+alpha", - "color-mapped-linear-gray", - "color-mapped-linear-gray+alpha", - "color-mapped-linear-bgr", - "color-mapped-linear-bgr+alpha", - "sRGB-gray", "alpha+sRGB-gray", "sRGB-rgb", @@ -390,16 +153,6 @@ static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = "alpha+linear-gray", "linear-rgb", "alpha+linear-rgb", - - "color-mapped-sRGB-gray", - "color-mapped-alpha+sRGB-gray", - "color-mapped-sRGB-rgb", - "color-mapped-alpha+sRGB-rgb", - "color-mapped-linear-gray", - "color-mapped-alpha+linear-gray", - "color-mapped-linear-rgb", - "color-mapped-alpha+linear-rgb", - "sRGB-gray", "alpha+sRGB-gray", "sRGB-bgr", @@ -408,15 +161,6 @@ static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = "alpha+linear-gray", "linear-bgr", "alpha+linear-bgr", - - "color-mapped-sRGB-gray", - "color-mapped-alpha+sRGB-gray", - "color-mapped-sRGB-bgr", - "color-mapped-alpha+sRGB-bgr", - "color-mapped-linear-gray", - "color-mapped-alpha+linear-gray", - "color-mapped-linear-bgr", - "color-mapped-alpha+linear-bgr", }; /* Decode an argument to a format number. */ @@ -426,107 +170,17 @@ formatof(const char *arg) char *ep; unsigned long format = strtoul(arg, &ep, 0); - if (ep > arg && *ep == 0 && format < FORMAT_COUNT) + if (ep > arg && *ep == 0 && format < 32) return (png_uint_32)format; - else for (format=0; format < FORMAT_COUNT; ++format) + else for (format=0; format < 32; ++format) { if (strcmp(format_names[format], arg) == 0) return (png_uint_32)format; } fprintf(stderr, "pngstest: format name '%s' invalid\n", arg); - return FORMAT_COUNT; -} - -/* Bitset/test functions for formats */ -#define FORMAT_SET_COUNT (FORMAT_COUNT / 32) -typedef struct -{ - png_uint_32 bits[FORMAT_SET_COUNT]; -} -format_list; - -static void format_init(format_list *pf) -{ - int i; - for (i=0; i<FORMAT_SET_COUNT; ++i) - pf->bits[i] = 0; /* All off */ -} - -#if 0 /* currently unused */ -static void format_clear(format_list *pf) -{ - int i; - for (i=0; i<FORMAT_SET_COUNT; ++i) - pf->bits[i] = 0; -} -#endif - -static int format_is_initial(format_list *pf) -{ - int i; - for (i=0; i<FORMAT_SET_COUNT; ++i) - if (pf->bits[i] != 0) - return 0; - - return 1; -} - -static int format_set(format_list *pf, png_uint_32 format) -{ - if (format < FORMAT_COUNT) - return pf->bits[format >> 5] |= ((png_uint_32)1) << (format & 31); - - return 0; -} - -#if 0 /* currently unused */ -static int format_unset(format_list *pf, png_uint_32 format) -{ - if (format < FORMAT_COUNT) - return pf->bits[format >> 5] &= ~((png_uint_32)1) << (format & 31); - - return 0; -} -#endif - -static int format_isset(format_list *pf, png_uint_32 format) -{ - return format < FORMAT_COUNT && - (pf->bits[format >> 5] & (((png_uint_32)1) << (format & 31))) != 0; -} - -static void format_default(format_list *pf, int redundant) -{ - if (redundant) - { - int i; - - /* set everything, including flags that are pointless */ - for (i=0; i<FORMAT_SET_COUNT; ++i) - pf->bits[i] = ~(png_uint_32)0; - } - - else - { - png_uint_32 f; - - for (f=0; f<FORMAT_COUNT; ++f) - { - /* Eliminate redundant settings. */ - /* BGR is meaningless if no color: */ - if ((f & PNG_FORMAT_FLAG_COLOR) == 0 && (f & PNG_FORMAT_FLAG_BGR) != 0) - continue; - - /* AFIRST is meaningless if no alpha: */ - if ((f & PNG_FORMAT_FLAG_ALPHA) == 0 && - (f & PNG_FORMAT_FLAG_AFIRST) != 0) - continue; - - format_set(pf, f); - } - } + return 32; } /* THE Image STRUCTURE */ @@ -546,8 +200,8 @@ typedef struct ptrdiff_t stride; png_size_t bufsize; png_size_t allocsize; + png_color background; char tmpfile_name[32]; - png_uint_16 colormap[256*4]; } Image; @@ -636,7 +290,6 @@ allocbuffer(Image *image) image->buffer = voidcast(png_bytep, malloc(size+32)); if (image->buffer == NULL) { - fflush(stdout); fprintf(stderr, "simpletest: out of memory allocating %lu(+32) byte buffer\n", (unsigned long)size); @@ -669,14 +322,12 @@ checkbuffer(Image *image, const char *arg) { if (check16(image->buffer, 95)) { - fflush(stdout); fprintf(stderr, "%s: overwrite at start of image buffer\n", arg); exit(1); } if (check16(image->buffer+16+image->allocsize, 95)) { - fflush(stdout); fprintf(stderr, "%s: overwrite at end of image buffer\n", arg); exit(1); } @@ -688,7 +339,6 @@ checkbuffer(Image *image, const char *arg) static int logerror(Image *image, const char *a1, const char *a2, const char *a3) { - fflush(stdout); if (image->image.warning_or_error) fprintf(stderr, "%s%s%s: %s\n", a1, a2, a3, image->image.message); @@ -729,9 +379,6 @@ checkopaque(Image *image) return logerror(image, image->file_name, ": opaque not NULL", ""); } - else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0) - return logerror(image, image->file_name, " --strict", ""); - else return 1; } @@ -742,2271 +389,896 @@ checkopaque(Image *image) */ typedef struct { - /* The components, for grayscale images the gray value is in 'g' and if alpha - * is not present 'a' is set to 255 or 65535 according to format. - */ - int r, g, b, a; + png_uint_32 format; + png_uint_16 r16, g16, b16, y16, a16; + png_byte r8, g8, b8, y8, a8; } Pixel; -typedef struct -{ - /* The background as the original sRGB 8-bit value converted to the final - * integer format and as a double precision linear value in the range 0..1 - * for with partially transparent pixels. - */ - int ir, ig, ib; - double dr, dg, db; /* linear r,g,b scaled to 0..1 */ -} Background; - -/* Basic image formats; control the data but not the layout thereof. */ -#define BASE_FORMATS\ - (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_LINEAR) - -/* Read a Pixel from a buffer. The code below stores the correct routine for - * the format in a function pointer, these are the routines: +/* This is not particularly fast, but it works. The input has pixels stored + * either as pre-multiplied linear 16-bit or as sRGB encoded non-pre-multiplied + * 8-bit values. The routine reads either and does exact conversion to the + * other format. + * + * Grayscale values are mapped r==g==b=y. Non-alpha images have alpha + * 65535/255. Color images have a correctly calculated Y value using the sRGB Y + * calculation. + * + * The API returns false if an error is detected; this can only be if the alpha + * value is less than the component in the linear case. */ -static void -gp_g8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = p->g = p->b = pp[0]; - p->a = 255; -} - -static void -gp_ga8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = p->g = p->b = pp[0]; - p->a = pp[1]; -} - -static void -gp_ag8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = p->g = p->b = pp[1]; - p->a = pp[0]; -} - -static void -gp_rgb8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = 255; -} - -static void -gp_bgr8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = 255; -} - -static void -gp_rgba8(Pixel *p, png_const_voidp pb) +static int +get_pixel(Image *image, Pixel *pixel, png_const_bytep pp) { - png_const_bytep pp = voidcast(png_const_bytep, pb); + png_uint_32 format = image->image.format; + int result = 1; - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = pp[3]; -} - -static void -gp_bgra8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = pp[3]; -} - -static void -gp_argb8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[1]; - p->g = pp[2]; - p->b = pp[3]; - p->a = pp[0]; -} - -static void -gp_abgr8(Pixel *p, png_const_voidp pb) -{ - png_const_bytep pp = voidcast(png_const_bytep, pb); - - p->r = pp[3]; - p->g = pp[2]; - p->b = pp[1]; - p->a = pp[0]; -} - -static void -gp_g16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = p->g = p->b = pp[0]; - p->a = 65535; -} - -static void -gp_ga16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = p->g = p->b = pp[0]; - p->a = pp[1]; -} - -static void -gp_ag16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = p->g = p->b = pp[1]; - p->a = pp[0]; -} - -static void -gp_rgb16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); - - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = 65535; -} + pixel->format = format; -static void -gp_bgr16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + /* Initialize the alpha values for opaque: */ + pixel->a8 = 255; + pixel->a16 = 65535; - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = 65535; -} + switch (PNG_IMAGE_COMPONENT_SIZE(format)) + { + default: + fprintf(stderr, "pngstest: impossible component size: %lu\n", + (unsigned long)PNG_IMAGE_COMPONENT_SIZE(format)); + exit(1); -static void -gp_rgba16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + case sizeof (png_uint_16): + { + png_const_uint_16p up = (png_const_uint_16p)pp; - p->r = pp[0]; - p->g = pp[1]; - p->b = pp[2]; - p->a = pp[3]; -} + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + pixel->a16 = *up++; -static void -gp_bgra16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + { + if ((format & PNG_FORMAT_FLAG_BGR) != 0) + { + pixel->b16 = *up++; + pixel->g16 = *up++; + pixel->r16 = *up++; + } - p->r = pp[2]; - p->g = pp[1]; - p->b = pp[0]; - p->a = pp[3]; -} + else + { + pixel->r16 = *up++; + pixel->g16 = *up++; + pixel->b16 = *up++; + } -static void -gp_argb16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + /* Because the 'Y' calculation is linear the pre-multiplication + * of the r16,g16,b16 values can be ignored. + */ + pixel->y16 = u16d(YfromRGBint(pixel->r16, pixel->g16, + pixel->b16)); + } - p->r = pp[1]; - p->g = pp[2]; - p->b = pp[3]; - p->a = pp[0]; -} + else + pixel->r16 = pixel->g16 = pixel->b16 = pixel->y16 = *up++; -static void -gp_abgr16(Pixel *p, png_const_voidp pb) -{ - png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); + if ((format & PNG_FORMAT_FLAG_AFIRST) == 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + pixel->a16 = *up++; - p->r = pp[3]; - p->g = pp[2]; - p->b = pp[1]; - p->a = pp[0]; -} + /* 'a1' is 1/65535 * 1/alpha, for alpha in the range 0..1 */ + if (pixel->a16 == 0) + { + pixel->r8 = pixel->g8 = pixel->b8 = pixel->y8 = 255; + pixel->a8 = 0; + } -/* Given a format, return the correct one of the above functions. */ -static void (* -get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb) -{ - /* The color-map flag is irrelevant here - the caller of the function - * returned must either pass the buffer or, for a color-mapped image, the - * correct entry in the color-map. - */ - if (format & PNG_FORMAT_FLAG_LINEAR) - { - if (format & PNG_FORMAT_FLAG_COLOR) - { - if (format & PNG_FORMAT_FLAG_BGR) - { - if (format & PNG_FORMAT_FLAG_ALPHA) + else { - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_abgr16; + double a1 = 1. / pixel->a16; + if (pixel->a16 < pixel->r16) + result = 0, pixel->r8 = 255; else - return gp_bgra16; - } + pixel->r8 = sRGB(pixel->r16 * a1); - else - return gp_bgr16; - } + if (pixel->a16 < pixel->g16) + result = 0, pixel->g8 = 255; + else + pixel->g8 = sRGB(pixel->g16 * a1); - else - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_argb16; + if (pixel->a16 < pixel->b16) + result = 0, pixel->b8 = 255; + else + pixel->b8 = sRGB(pixel->b16 * a1); + if (pixel->a16 < pixel->y16) + result = 0, pixel->y8 = 255; else - return gp_rgba16; - } + pixel->y8 = sRGB(pixel->y16 * a1); - else - return gp_rgb16; + /* The 8-bit alpha value is just a16/257. */ + pixel->a8 = u8d(pixel->a16 / 257.); + } } - } + break; - else - { - if (format & PNG_FORMAT_FLAG_ALPHA) + case sizeof (png_byte): { - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_ag16; + double y; - else - return gp_ga16; - } - - else - return gp_g16; - } - } + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + pixel->a8 = *pp++; - else - { - if (format & PNG_FORMAT_FLAG_COLOR) - { - if (format & PNG_FORMAT_FLAG_BGR) - { - if (format & PNG_FORMAT_FLAG_ALPHA) + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) { - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_abgr8; + if ((format & PNG_FORMAT_FLAG_BGR) != 0) + { + pixel->b8 = *pp++; + pixel->g8 = *pp++; + pixel->r8 = *pp++; + } else - return gp_bgra8; - } - - else - return gp_bgr8; - } + { + pixel->r8 = *pp++; + pixel->g8 = *pp++; + pixel->b8 = *pp++; + } - else - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_argb8; + /* The y8 value requires convert to linear, convert to &, convert + * to sRGB: + */ + y = YfromRGB(linear_from_sRGB(pixel->r8/255.), + linear_from_sRGB(pixel->g8/255.), + linear_from_sRGB(pixel->b8/255.)); - else - return gp_rgba8; + pixel->y8 = sRGB(y); } else - return gp_rgb8; - } - } + { + pixel->r8 = pixel->g8 = pixel->b8 = pixel->y8 = *pp++; + y = linear_from_sRGB(pixel->y8/255.); + } - else - { - if (format & PNG_FORMAT_FLAG_ALPHA) - { - if (format & PNG_FORMAT_FLAG_AFIRST) - return gp_ag8; + if ((format & PNG_FORMAT_FLAG_AFIRST) == 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + pixel->a8 = *pp++; - else - return gp_ga8; + pixel->r16 = ilineara(pixel->r8, pixel->a8); + pixel->g16 = ilineara(pixel->g8, pixel->a8); + pixel->b16 = ilineara(pixel->b8, pixel->a8); + pixel->y16 = u16d((257 * pixel->a8) * y); + pixel->a16 = (png_uint_16)(pixel->a8 * 257); } - - else - return gp_g8; - } + break; } + + return result; } -/* Convertion between pixel formats. The code above effectively eliminates the - * component ordering changes leaving three basic changes: - * - * 1) Remove an alpha channel by pre-multiplication or compositing on a - * background color. (Adding an alpha channel is a no-op.) - * - * 2) Remove color by mapping to grayscale. (Grayscale to color is a no-op.) - * - * 3) Convert between 8-bit and 16-bit components. (Both directtions are - * relevant.) - * - * This gives the following base format conversion matrix: +/* Two pixels are equal if the value of the left equals the value of the right + * as defined by the format of the right, or if it is close enough given the + * permitted error limits. If the formats match the values should (exactly!) * - * OUT: ----- 8-bit ----- ----- 16-bit ----- - * IN G GA RGB RGBA G GA RGB RGBA - * 8 G . . . . lin lin lin lin - * 8 GA bckg . bckc . pre' pre pre' pre - * 8 RGB g8 g8 . . glin glin lin lin - * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre - * 16 G sRGB sRGB sRGB sRGB . . . . - * 16 GA b16g unpg b16c unpc A . A . - * 16 RGB sG sG sRGB sRGB g16 g16 . . - * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . + * If the right pixel has no alpha channel but the left does, it was removed + * somehow. For an 8-bit *output* removal uses the background color if given + * else the default (the value filled in to the row buffer by allocbuffer() + * above.) * - * 8-bit to 8-bit: - * bckg: composite on gray background - * bckc: composite on color background - * g8: convert sRGB components to sRGB grayscale - * g8b: convert sRGB components to grayscale and composite on gray background + * The result of this function is NULL if the pixels match else a reason why + * they don't match. * - * 8-bit to 16-bit: - * lin: make sRGB components linear, alpha := 65535 - * pre: make sRGB components linear and premultiply by alpha (scale alpha) - * pre': as 'pre' but alpha := 65535 - * glin: make sRGB components linear, convert to grayscale, alpha := 65535 - * gpre: make sRGB components grayscale and linear and premultiply by alpha - * gpr': as 'gpre' but alpha := 65535 - * - * 16-bit to 8-bit: - * sRGB: convert linear components to sRGB, alpha := 255 - * unpg: unpremultiply gray component and convert to sRGB (scale alpha) - * unpc: unpremultiply color components and convert to sRGB (scale alpha) - * b16g: composite linear onto gray background and convert the result to sRGB - * b16c: composite linear onto color background and convert the result to sRGB - * sG: convert linear RGB to sRGB grayscale - * sGp: unpremultiply RGB then convert to sRGB grayscale - * sCp: unpremultiply RGB then convert to sRGB - * gb16: composite linear onto background and convert to sRGB grayscale - * (order doesn't matter, the composite and grayscale operations permute) - * cb16: composite linear onto background and convert to sRGB - * - * 16-bit to 16-bit: - * A: set alpha to 65535 - * g16: convert linear RGB to linear grayscale (alpha := 65535) - * g16': as 'g16' but alpha is unchanged + * Error values below are inflated because some of the conversions are done + * inside libpng using a simple power law transform of .45455 and others are + * done in the simplified API code using the correct sRGB tables. This needs + * to be made consistent. */ -/* Simple copy: */ -static void -gpc_noop(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = in->r; - out->g = in->g; - out->b = in->b; - out->a = in->a; -} - -#if ALLOW_UNUSED_GPC -static void -gpc_nop8(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - if (in->a == 0) - out->r = out->g = out->b = 255; - - else - { - out->r = in->r; - out->g = in->g; - out->b = in->b; - } - - out->a = in->a; -} -#endif - -#if ALLOW_UNUSED_GPC -static void -gpc_nop6(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - if (in->a == 0) - out->r = out->g = out->b = 65535; - - else - { - out->r = in->r; - out->g = in->g; - out->b = in->b; - } - - out->a = in->a; -} -#endif - -/* 8-bit to 8-bit conversions */ -/* bckg: composite on gray background */ -static void -gpc_bckg(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else if (in->a >= 255) - out->r = out->g = out->b = in->g; - - else - { - double a = in->a / 255.; - - out->r = out->g = out->b = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); - } - - out->a = 255; -} - -/* bckc: composite on color background */ -static void -gpc_bckc(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - { - out->r = back->ir; - out->g = back->ig; - out->b = back->ib; - } - - else if (in->a >= 255) - { - out->r = in->r; - out->g = in->g; - out->b = in->b; - } - - else - { - double a = in->a / 255.; - - out->r = sRGB(sRGB_to_d[in->r] * a + back->dr * (1-a)); - out->g = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); - out->b = sRGB(sRGB_to_d[in->b] * a + back->db * (1-a)); - } - - out->a = 255; -} - -/* g8: convert sRGB components to sRGB grayscale */ -static void -gpc_g8(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = in->g; - - else - out->r = out->g = out->b = - sRGB(YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = in->a; -} - -/* g8b: convert sRGB components to grayscale and composite on gray background */ -static void -gpc_g8b(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else if (in->a >= 255) - { - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = in->g; - - else - out->r = out->g = out->b = sRGB(YfromRGB( - sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - } - - else - { - double a = in->a/255.; - - out->r = out->g = out->b = sRGB(a * YfromRGB(sRGB_to_d[in->r], - sRGB_to_d[in->g], sRGB_to_d[in->b]) + back->dg * (1-a)); - } - - out->a = 255; -} - -/* 8-bit to 16-bit conversions */ -/* lin: make sRGB components linear, alpha := 65535 */ -static void -gpc_lin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilinear(in->r); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilinear(in->b); - } - - else - { - out->g = ilinear(in->g); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilinear(in->b); - } - - out->a = 65535; -} - -/* pre: make sRGB components linear and premultiply by alpha (scale alpha) */ -static void -gpc_pre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilineara(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilineara(in->b, in->a); - } - - else - { - out->g = ilineara(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara(in->b, in->a); - } - - out->a = in->a * 257; -} - -/* pre': as 'pre' but alpha := 65535 */ -static void -gpc_preq(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilineara(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilineara(in->b, in->a); - } - - else - { - out->g = ilineara(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara(in->b, in->a); - } - - out->a = 65535; -} - -/* glin: make sRGB components linear, convert to grayscale, alpha := 65535 */ -static void -gpc_glin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilinear(in->g); - - else - out->r = out->g = out->b = u16d(65535 * - YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = 65535; -} - -/* gpre: make sRGB components grayscale and linear and premultiply by alpha */ -static void -gpc_gpre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara(in->g, in->a); - - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = 257 * in->a; -} - -/* gpr': as 'gpre' but alpha := 65535 */ -static void -gpc_gprq(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara(in->g, in->a); - - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); - - out->a = 65535; -} - -/* 8-bit to 16-bit conversions for gAMA 45455 encoded values */ -/* Lin: make gAMA 45455 components linear, alpha := 65535 */ -static void -gpc_Lin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilinear_g22(in->r); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilinear_g22(in->b); - } - - else - { - out->g = ilinear_g22(in->g); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilinear_g22(in->b); - } - - out->a = 65535; -} - -#if ALLOW_UNUSED_GPC -/* Pre: make gAMA 45455 components linear and premultiply by alpha (scale alpha) - */ -static void -gpc_Pre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = ilineara_g22(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; - - else - out->b = ilineara_g22(in->b, in->a); - } - - else - { - out->g = ilineara_g22(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara_g22(in->b, in->a); - } - - out->a = in->a * 257; -} -#endif +static int error_to_linear = 811; /* by experiment */ +static int error_to_linear_grayscale = 424; /* by experiment */ +static int error_to_sRGB = 6; /* by experiment */ +static int error_to_sRGB_grayscale = 11; /* by experiment */ +static int error_in_compose = 0; +static int error_via_linear = 14; /* by experiment */ +static int error_in_premultiply = 1; -#if ALLOW_UNUSED_GPC -/* Pre': as 'Pre' but alpha := 65535 */ -static void -gpc_Preq(Pixel *out, const Pixel *in, const Background *back) +static const char * +cmppixel(Pixel *a, Pixel *b, const png_color *background, int via_linear) { - (void)back; - - out->r = ilineara_g22(in->r, in->a); - - if (in->g == in->r) - { - out->g = out->r; - - if (in->b == in->r) - out->b = out->r; + int error_limit = 0; - else - out->b = ilineara_g22(in->b, in->a); - } - - else + if (b->format & PNG_FORMAT_FLAG_LINEAR) { - out->g = ilineara_g22(in->g, in->a); - - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; - - else - out->b = ilineara_g22(in->b, in->a); - } - - out->a = 65535; -} -#endif - -#if ALLOW_UNUSED_GPC -/* Glin: make gAMA 45455 components linear, convert to grayscale, alpha := 65535 - */ -static void -gpc_Glin(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilinear_g22(in->g); + /* If the input was non-opaque then use the pre-multiplication error + * limit. + */ + if ((a->format & PNG_FORMAT_FLAG_ALPHA) && a->a16 < 65535) + error_limit = error_in_premultiply; - else - out->r = out->g = out->b = u16d(65535 * - YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + if (b->format & PNG_FORMAT_FLAG_ALPHA) + { + /* Expect an exact match. */ + if (b->a16 != a->a16) + return "linear alpha mismatch"; + } - out->a = 65535; -} -#endif + else if (a->format & PNG_FORMAT_FLAG_ALPHA) + { + /* An alpha channel has been removed, the destination is linear so the + * removal algorithm is just the premultiplication - compose on black - + * and the 16-bit colors are correct already. + */ + } -#if ALLOW_UNUSED_GPC -/* Gpre: make gAMA 45455 components grayscale and linear and premultiply by - * alpha. - */ -static void -gpc_Gpre(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; + if (b->format & PNG_FORMAT_FLAG_COLOR) + { + const char *err = "linear color mismatch"; - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara_g22(in->g, in->a); + /* Check for an exact match. */ + if (a->r16 == b->r16 && a->g16 == b->g16 && a->b16 == b->b16) + return NULL; - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + /* Not an exact match; allow drift only if the input is 8-bit */ + if (!(a->format & PNG_FORMAT_FLAG_LINEAR)) + { + if (error_limit < error_to_linear) + { + error_limit = error_to_linear; + err = "sRGB to linear conversion error"; + } + } - out->a = 257 * in->a; -} -#endif + if (abs(a->r16-b->r16) <= error_limit && + abs(a->g16-b->g16) <= error_limit && + abs(a->b16-b->b16) <= error_limit) + return NULL; -#if ALLOW_UNUSED_GPC -/* Gpr': as 'Gpre' but alpha := 65535 */ -static void -gpc_Gprq(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; + return err; + } - if (in->r == in->g && in->g == in->b) - out->r = out->g = out->b = ilineara_g22(in->g, in->a); + else /* b is grayscale */ + { + const char *err = "linear gray mismatch"; - else - out->r = out->g = out->b = u16d(in->a * 257 * - YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); + /* Check for an exact match. */ + if (a->y16 == b->y16) + return NULL; - out->a = 65535; -} -#endif + /* Not an exact match; allow drift only if the input is 8-bit or if it + * has been converted from color. + */ + if (!(a->format & PNG_FORMAT_FLAG_LINEAR)) + { + /* Converted to linear, check for that drift. */ + if (error_limit < error_to_linear) + { + error_limit = error_to_linear; + err = "8-bit gray to linear conversion error"; + } -/* 16-bit to 8-bit conversions */ -/* sRGB: convert linear components to sRGB, alpha := 255 */ -static void -gpc_sRGB(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; + if (abs(a->y16-b->y16) <= error_to_linear) + return NULL; - out->r = isRGB(in->r); + } - if (in->g == in->r) - { - out->g = out->r; + if (a->format & PNG_FORMAT_FLAG_COLOR) + { + /* Converted to grayscale, allow drift */ + if (error_limit < error_to_linear_grayscale) + { + error_limit = error_to_linear_grayscale; + err = "color to linear gray conversion error"; + } + } - if (in->b == in->r) - out->b = out->r; + if (abs(a->y16-b->y16) <= error_limit) + return NULL; - else - out->b = isRGB(in->b); + return err; + } } - else + else /* RHS is 8-bit */ { - out->g = isRGB(in->g); + const char *err; - if (in->b == in->r) - out->b = out->r; - - else if (in->b == in->g) - out->b = out->g; + /* For 8-bit to 8-bit use 'error_via_linear'; this handles the cases where + * the original image is compared with the output of another conversion: + * see where the parameter is set to non-zero below. + */ + if (!(a->format & PNG_FORMAT_FLAG_LINEAR) && via_linear) + error_limit = error_via_linear; + if (b->format & PNG_FORMAT_FLAG_COLOR) + err = "8-bit color mismatch"; + else - out->b = isRGB(in->b); - } - - out->a = 255; -} + err = "8-bit gray mismatch"; -/* unpg: unpremultiply gray component and convert to sRGB (scale alpha) */ -static void -gpc_unpg(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = out->g = out->b = sRGB((double)in->g / in->a); - out->a = u8d(in->a / 257.); - } -} - -/* unpc: unpremultiply color components and convert to sRGB (scale alpha) */ -static void -gpc_unpc(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = sRGB((double)in->r / in->a); - out->g = sRGB((double)in->g / in->a); - out->b = sRGB((double)in->b / in->a); - out->a = u8d(in->a / 257.); - } -} - -/* b16g: composite linear onto gray background and convert the result to sRGB */ -static void -gpc_b16g(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else - { - double a = in->a/65535.; - double a1 = 1-a; - - a /= 65535; - out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); - } - - out->a = 255; -} - -/* b16c: composite linear onto color background and convert the result to sRGB*/ -static void -gpc_b16c(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - { - out->r = back->ir; - out->g = back->ig; - out->b = back->ib; - } - - else - { - double a = in->a/65535.; - double a1 = 1-a; - - a /= 65535; - out->r = sRGB(in->r * a + back->dr * a1); - out->g = sRGB(in->g * a + back->dg * a1); - out->b = sRGB(in->b * a + back->db * a1); - } - - out->a = 255; -} - -/* sG: convert linear RGB to sRGB grayscale */ -static void -gpc_sG(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/65535); - out->a = 255; -} - -/* sGp: unpremultiply RGB then convert to sRGB grayscale */ -static void -gpc_sGp(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/in->a); - out->a = u8d(in->a / 257.); - } -} - -/* sCp: unpremultiply RGB then convert to sRGB */ -static void -gpc_sCp(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - - if (in->a <= 128) - { - out->r = out->g = out->b = 255; - out->a = 0; - } - - else - { - out->r = sRGB((double)in->r / in->a); - out->g = sRGB((double)in->g / in->a); - out->b = sRGB((double)in->b / in->a); - out->a = u8d(in->a / 257.); - } -} - -/* gb16: composite linear onto background and convert to sRGB grayscale */ -/* (order doesn't matter, the composite and grayscale operations permute) */ -static void -gpc_gb16(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - out->r = out->g = out->b = back->ig; - - else if (in->a >= 65535) - out->r = out->g = out->b = isRGB(in->g); - - else - { - double a = in->a / 65535.; - double a1 = 1-a; - - a /= 65535; - out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); - } + /* If the original data had an alpha channel and was not pre-multiplied + * pre-multiplication may lose precision in non-opaque pixel values. If + * the output is linear the premultiplied 16-bit values will be used, but + * if 'via_linear' is set an intermediate 16-bit pre-multiplied form has + * been used and this must be taken into account here. + */ + if (via_linear && (a->format & PNG_FORMAT_FLAG_ALPHA) && + !(a->format & PNG_FORMAT_FLAG_LINEAR) && + a->a16 < 65535) + { + if (a->a16 > 0) + { + /* First calculate the rounded 16-bit component values, (r,g,b) or y + * as appropriate, then back-calculate the 8-bit values for + * comparison below. + */ + if (a->format & PNG_FORMAT_FLAG_COLOR) + { + double r = closestinteger((65535. * a->r16) / a->a16)/65535; + double g = closestinteger((65535. * a->g16) / a->a16)/65535; + double blue = closestinteger((65535. * a->b16) / a->a16)/65535; + + a->r16 = u16d(r * a->a16); + a->g16 = u16d(g * a->a16); + a->b16 = u16d(blue * a->a16); + a->y16 = u16d(YfromRGBint(a->r16, a->g16, a->b16)); + + a->r8 = u8d(r * 255); + a->g8 = u8d(g * 255); + a->b8 = u8d(blue * 255); + a->y8 = u8d(255 * YfromRGB(r, g, blue)); + } - out->a = 255; -} + else + { + double y = closestinteger((65535. * a->y16) / a->a16)/65535.; -/* cb16: composite linear onto background and convert to sRGB */ -static void -gpc_cb16(Pixel *out, const Pixel *in, const Background *back) -{ - if (in->a <= 0) - { - out->r = back->ir; - out->g = back->ig; - out->b = back->ib; - } + a->b16 = a->g16 = a->r16 = a->y16 = u16d(y * a->a16); + a->b8 = a->g8 = a->r8 = a->y8 = u8d(255 * y); + } + } - else if (in->a >= 65535) - { - out->r = isRGB(in->r); - out->g = isRGB(in->g); - out->b = isRGB(in->b); - } + else + { + a->r16 = a->g16 = a->b16 = a->y16 = 0; + a->r8 = a->g8 = a->b8 = a->y8 = 255; + } + } - else - { - double a = in->a / 65535.; - double a1 = 1-a; - a /= 65535; - out->r = sRGB(in->r * a + back->dr * a1); - out->g = sRGB(in->g * a + back->dg * a1); - out->b = sRGB(in->b * a + back->db * a1); - } + if (b->format & PNG_FORMAT_FLAG_ALPHA) + { + /* Expect an exact match on the 8 bit value. */ + if (b->a8 != a->a8) + return "8-bit alpha mismatch"; + + /* If the *input* was linear+alpha as well libpng will have converted + * the non-premultiplied format directly to the sRGB non-premultiplied + * format and the precision loss on an intermediate pre-multiplied + * format will have been avoided. In this case we will get spurious + * values in the non-opaque pixels. + */ + if (!via_linear && (a->format & PNG_FORMAT_FLAG_LINEAR) != 0 && + (a->format & PNG_FORMAT_FLAG_ALPHA) != 0 && + a->a16 < 65535) + { + /* We don't know the original values (libpng has already removed + * them) but we can make sure they are in range here by doing a + * comparison on the pre-multiplied values instead. + */ + if (a->a16 > 0) + { + if (b->format & PNG_FORMAT_FLAG_COLOR) + { + double r, g, blue; - out->a = 255; -} + r = (255. * b->r16)/b->a16; + b->r8 = u8d(r); -/* 16-bit to 16-bit conversions */ -/* A: set alpha to 65535 */ -static void -gpc_A(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = in->r; - out->g = in->g; - out->b = in->b; - out->a = 65535; -} + g = (255. * b->g16)/b->a16; + b->g8 = u8d(g); -/* g16: convert linear RGB to linear grayscale (alpha := 65535) */ -static void -gpc_g16(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); - out->a = 65535; -} + blue = (255. * b->b16)/b->a16; + b->b8 = u8d(blue); -/* g16': as 'g16' but alpha is unchanged */ -static void -gpc_g16q(Pixel *out, const Pixel *in, const Background *back) -{ - (void)back; - out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); - out->a = in->a; -} + b->y8 = u8d(YfromRGB(r, g, blue)); + } -#if ALLOW_UNUSED_GPC -/* Unused functions (to hide them from GCC unused function warnings) */ -void (* const gpc_unused[]) - (Pixel *out, const Pixel *in, const Background *back) = -{ - gpc_Pre, gpc_Preq, gpc_Glin, gpc_Gpre, gpc_Gprq, gpc_nop8, gpc_nop6 -}; -#endif + else + { + b->r8 = b->g8 = b->b8 = b->y8 = + u8d((255. * b->y16)/b->a16); + } + } -/* OUT: ----- 8-bit ----- ----- 16-bit ----- - * IN G GA RGB RGBA G GA RGB RGBA - * 8 G . . . . lin lin lin lin - * 8 GA bckg . bckc . pre' pre pre' pre - * 8 RGB g8 g8 . . glin glin lin lin - * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre - * 16 G sRGB sRGB sRGB sRGB . . . . - * 16 GA b16g unpg b16c unpc A . A . - * 16 RGB sG sG sRGB sRGB g16 g16 . . - * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . - * - * The matrix is held in an array indexed thus: - * - * gpc_fn[out_format & BASE_FORMATS][in_format & BASE_FORMATS]; - */ -/* This will produce a compile time error if the FORMAT_FLAG values don't - * match the above matrix! - */ -#if PNG_FORMAT_FLAG_ALPHA == 1 && PNG_FORMAT_FLAG_COLOR == 2 &&\ - PNG_FORMAT_FLAG_LINEAR == 4 -static void (* const gpc_fn[8/*in*/][8/*out*/]) - (Pixel *out, const Pixel *in, const Background *back) = -{ -/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ - {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_Lin, gpc_Lin, gpc_Lin, gpc_Lin }, - {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, - {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, - {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, - {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, - {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, - {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, - {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} -}; + else + b->r8 = b->g8 = b->b8 = b->y8 = 255; + } + } -/* The array is repeated for the cases where both the input and output are color - * mapped because then different algorithms are used. - */ -static void (* const gpc_fn_colormapped[8/*in*/][8/*out*/]) - (Pixel *out, const Pixel *in, const Background *back) = -{ -/*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ - {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_lin, gpc_lin, gpc_lin, gpc_lin }, - {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, - {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, - {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, - {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, - {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, - {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, - {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} -}; + else if (a->format & PNG_FORMAT_FLAG_ALPHA) + { + png_uint_32 alpha; -/* The error arrays record the error in the same matrix; 64 entries, however - * the different algorithms used in libpng for colormap and direct conversions - * mean that four separate matrices are used (for each combination of - * colormapped and direct.) - * - * In some cases the conversion between sRGB formats goes via a linear - * intermediate; an sRGB to linear conversion (as above) is followed by a simple - * linear to sRGB step with no other conversions. This is done by a separate - * error array from an arbitrary 'in' format to one of the four basic outputs - * (since final output is always sRGB not colormapped). - * - * These arrays may be modified if the --accumulate flag is set during the run; - * then instead of logging errors they are simply added in. - * - * The three entries are currently for transparent, partially transparent and - * opaque input pixel values. Notice that alpha should be exact in each case. - * - * Errors in alpha should only occur when converting from a direct format - * to a colormapped format, when alpha is effectively smashed (so large - * errors can occur.) There should be no error in the '0' and 'opaque' - * values. The fourth entry in the array is used for the alpha error (and it - * should always be zero for the 'via linear' case since this is never color - * mapped.) - * - * Mapping to a colormap smashes the colors, it is necessary to have separate - * values for these cases because they are much larger; it is very much - * impossible to obtain a reasonable result, these are held in - * gpc_error_to_colormap. - */ -#if PNG_FORMAT_FLAG_COLORMAP == 8 /* extra check also required */ -/* START MACHINE GENERATED */ -static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] = -{ - { /* input: sRGB-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: sRGB-gray+alpha */ - { 0, 18, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: sRGB-rgb */ - { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: sRGB-rgb+alpha */ - { 0, 4, 13, 0 }, { 0, 14, 13, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 832, 764, 0 }, { 0, 832, 764, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-gray */ - { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-gray+alpha */ - { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, - { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-rgb */ - { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, - { 0, 0, 4, 0 }, { 0, 0, 4, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: linear-rgb+alpha */ - { 0, 126, 143, 0 }, { 0, 9, 7, 0 }, { 0, 74, 9, 0 }, { 0, 16, 9, 0 }, - { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-rgb */ - { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 8, 0 }, { 0, 0, 8, 0 }, - { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 }, - { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 } - }, { /* input: color-mapped-sRGB-rgb+alpha */ - { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 8, 0 }, { 0, 9, 8, 0 }, - { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 409, 0 }, { 0, 717, 409, 0 }, - { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 13323, 460, 0 }, { 0, 334, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 } - }, { /* input: color-mapped-linear-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 } - } -}; -static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] = -{ - { /* input: sRGB-gray */ - { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 } - }, { /* input: sRGB-gray+alpha */ - { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 } - }, { /* input: sRGB-rgb */ - { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 } - }, { /* input: sRGB-rgb+alpha */ - { 0, 12, 14, 0 }, { 0, 180, 14, 0 }, { 0, 14, 15, 0 }, { 0, 186, 15, 0 } - }, { /* input: linear-gray */ - { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } - }, { /* input: linear-gray+alpha */ - { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } - }, { /* input: linear-rgb */ - { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } - }, { /* input: linear-rgb+alpha */ - { 0, 1, 1, 0 }, { 0, 8, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } - }, { /* input: color-mapped-sRGB-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-sRGB-rgb */ - { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 } - }, { /* input: color-mapped-sRGB-rgb+alpha */ - { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 8, 3, 0 }, { 0, 32, 3, 0 } - }, { /* input: color-mapped-linear-gray */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-gray+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - }, { /* input: color-mapped-linear-rgb+alpha */ - { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } - } -}; -static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] = -{ - { /* input: sRGB-gray */ - { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, - { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 } - }, { /* input: sRGB-gray+alpha */ - { 0, 19, 2, 0 }, { 0, 255, 2, 25 }, { 0, 88, 2, 0 }, { 0, 255, 2, 25 }, - { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }, { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 } - }, { /* input: sRGB-rgb */ - { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 }, - { 0, 0, 937, 0 }, { 0, 0, 937, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 } - }, { /* input: sRGB-rgb+alpha */ - { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 220, 25, 0 }, { 0, 255, 25, 67 }, - { 0, 17534, 18491, 0 }, { 0, 15614, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 48573, 13677, 17219 } - }, { /* input: linear-gray */ - { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, - { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 } - }, { /* input: linear-gray+alpha */ - { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 97, 74, 0 }, { 0, 255, 74, 25 }, - { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 } - }, { /* input: linear-rgb */ - { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 }, - { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 } - }, { /* input: linear-rgb+alpha */ - { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 }, - { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 46509, 24992, 17347 } - } -}; -/* END MACHINE GENERATED */ -#endif /* COLORMAP flag check */ -#endif /* flag checks */ + /* An alpha channel has been removed; the background will have been + * composed in. Adjust the 'a' pixel to represent this by doing the + * correct compose. Set the error limit, above, to an appropriate + * value for the compose operation. + */ + if (error_limit < error_in_compose) + error_limit = error_in_compose; -typedef struct -{ - /* Basic pixel information: */ - Image* in_image; /* Input image */ - const Image* out_image; /* Output image */ + alpha = 65535 - a->a16; /* for the background */ - /* 'background' is the value passed to the gpc_ routines, it may be NULL if - * it should not be used (*this* program has an error if it crashes as a - * result!) - */ - Background background_color; - const Background* background; + if (b->format & PNG_FORMAT_FLAG_COLOR) /* background is rgb */ + { + err = "8-bit color compose error"; - /* Precalculated values: */ - int in_opaque; /* Value of input alpha that is opaque */ - int is_palette; /* Sample values come from the palette */ - int accumulate; /* Accumlate component errors (don't log) */ - int output_8bit; /* Output is 8 bit (else 16 bit) */ + if (via_linear) + { + /* The 16-bit values are already correct (being pre-multiplied), + * just recalculate the 8-bit values. + */ + a->r8 = isRGB(a->r16); + a->g8 = isRGB(a->g16); + a->b8 = isRGB(a->b16); + a->y8 = isRGB(a->y16); - void (*in_gp)(Pixel*, png_const_voidp); - void (*out_gp)(Pixel*, png_const_voidp); + /* There should be no libpng error in this (ideally) */ + error_limit = 0; + } - void (*transform)(Pixel *out, const Pixel *in, const Background *back); - /* A function to perform the required transform */ + else if (background == NULL) + { + double add = alpha * linear_from_sRGB(BUFFER_INIT8/255.); + double r, g, blue, y; - void (*from_linear)(Pixel *out, const Pixel *in, const Background *back); - /* For 'via_linear' transforms the final, from linear, step, else NULL */ + r = a->r16 + add; + a->r16 = u16d(r); + a->r8 = sRGB(r/65535); - png_uint_16 error[4]; - /* Three error values for transparent, partially transparent and opaque - * input pixels (in turn). - */ + g = a->g16 + add; + a->g16 = u16d(g); + a->g8 = sRGB(g/65535); - png_uint_16 *error_ptr; - /* Where these are stored in the static array (for 'accumulate') */ -} -Transform; + blue = a->b16 + add; + a->b16 = u16d(blue); + a->b8 = sRGB(blue/65535); -/* Return a 'transform' as above for the given format conversion. */ -static void -transform_from_formats(Transform *result, Image *in_image, - const Image *out_image, png_const_colorp background, int via_linear) -{ - png_uint_32 in_format, out_format; - png_uint_32 in_base, out_base; + y = YfromRGB(r, g, blue); + a->y16 = u16d(y); + a->y8 = sRGB(y/65535); + } - memset(result, 0, sizeof *result); + else + { + double r, g, blue, y; - /* Store the original images for error messages */ - result->in_image = in_image; - result->out_image = out_image; + r = a->r16 + alpha * linear_from_sRGB(background->red/255.); + a->r16 = u16d(r); + a->r8 = sRGB(r/65535); - in_format = in_image->image.format; - out_format = out_image->image.format; + g = a->g16 + alpha * linear_from_sRGB(background->green/255.); + a->g16 = u16d(g); + a->g8 = sRGB(g/65535); - if (in_format & PNG_FORMAT_FLAG_LINEAR) - result->in_opaque = 65535; - else - result->in_opaque = 255; + blue = a->b16 + alpha * linear_from_sRGB(background->blue/255.); + a->b16 = u16d(blue); + a->b8 = sRGB(blue/65535); - result->output_8bit = (out_format & PNG_FORMAT_FLAG_LINEAR) == 0; + y = YfromRGB(r, g, blue); + a->y16 = u16d(y * 65535); + a->y8 = sRGB(y); + } + } - result->is_palette = 0; /* set by caller if required */ - result->accumulate = (in_image->opts & ACCUMULATE) != 0; + else /* background is gray */ + { + err = "8-bit gray compose error"; - /* The loaders (which need the ordering information) */ - result->in_gp = get_pixel(in_format); - result->out_gp = get_pixel(out_format); + if (via_linear) + { + a->r8 = a->g8 = a->b8 = a->y8 = isRGB(a->y16); + error_limit = 0; + } - /* Remove the ordering information: */ - in_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; - in_base = in_format & BASE_FORMATS; - out_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; - out_base = out_format & BASE_FORMATS; + else + { + /* When the output is gray the background comes from just the + * green channel. + */ + double y = a->y16 + alpha * linear_from_sRGB( + (background == NULL ? BUFFER_INIT8 : background->green)/255.); - if (via_linear) - { - /* Check for an error in this program: */ - if (out_format & (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLORMAP)) - { - fprintf(stderr, "internal transform via linear error 0x%x->0x%x\n", - in_format, out_format); - exit(1); + a->r16 = a->g16 = a->b16 = a->y16 = u16d(y); + a->r8 = a->g8 = a->b8 = a->y8 = sRGB(y/65535); + } + } } - result->transform = gpc_fn[in_base][out_base | PNG_FORMAT_FLAG_LINEAR]; - result->from_linear = gpc_fn[out_base | PNG_FORMAT_FLAG_LINEAR][out_base]; - result->error_ptr = gpc_error_via_linear[in_format][out_format]; - } - - else if (~in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) - { - /* The input is not colormapped but the output is, the errors will - * typically be large (only the grayscale-no-alpha case permits preserving - * even 8-bit values.) - */ - result->transform = gpc_fn[in_base][out_base]; - result->from_linear = NULL; - result->error_ptr = gpc_error_to_colormap[in_base][out_base]; - } - - else - { - /* The caller handles the colormap->pixel value conversion, so the - * transform function just gets a pixel value, however because libpng - * currently contains a different implementation for mapping a colormap if - * both input and output are colormapped we need different conversion - * functions to deal with errors in the libpng implementation. - */ - if (in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) - result->transform = gpc_fn_colormapped[in_base][out_base]; - else - result->transform = gpc_fn[in_base][out_base]; - result->from_linear = NULL; - result->error_ptr = gpc_error[in_format][out_format]; - } - - /* Follow the libpng simplified API rules to work out what to pass to the gpc - * routines as a background value, if one is not required pass NULL so that - * this program crashes in the even of a programming error. - */ - result->background = NULL; /* default: not required */ + if (b->format & PNG_FORMAT_FLAG_COLOR) + { - /* Rule 1: background only need be supplied if alpha is to be removed */ - if (in_format & ~out_format & PNG_FORMAT_FLAG_ALPHA) - { - /* The input value is 'NULL' to use the background and (otherwise) an sRGB - * background color (to use a solid color). The code above uses a fixed - * byte value, BUFFER_INIT8, for buffer even for 16-bit output. For - * linear (16-bit) output the sRGB background color is ignored; the - * composition is always on the background (so BUFFER_INIT8 * 257), except - * that for the colormap (i.e. linear colormapped output) black is used. - */ - result->background = &result->background_color; + /* Check for an exact match. */ + if (a->r8 == b->r8 && a->g8 == b->g8 && a->b8 == b->b8) + return NULL; - if (out_format & PNG_FORMAT_FLAG_LINEAR || via_linear) - { - if (out_format & PNG_FORMAT_FLAG_COLORMAP) + /* Check for linear to 8-bit conversion. */ + if (a->format & PNG_FORMAT_FLAG_LINEAR) { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = 0; - result->background_color.dr = - result->background_color.dg = - result->background_color.db = 0; + if (error_limit < error_to_sRGB) + { + err = "linear to sRGB conversion error"; + error_limit = error_to_sRGB; + } } - else - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = BUFFER_INIT8 * 257; - result->background_color.dr = - result->background_color.dg = - result->background_color.db = 0; - } + if (abs(a->r8-b->r8) <= error_limit && + abs(a->g8-b->g8) <= error_limit && + abs(a->b8-b->b8) <= error_limit) + return NULL; + + return err; } - else /* sRGB output */ + else /* b is grayscale */ { - if (background != NULL) + /* Check for an exact match. */ + if (a->y8 == b->y8) + return NULL; + + /* Not an exact match; allow drift only if the input is linear or if it + * has been converted from color. + */ + if (a->format & PNG_FORMAT_FLAG_LINEAR) { - if (out_format & PNG_FORMAT_FLAG_COLOR) + /* Converted to linear, check for that drift. */ + if (error_limit < error_to_sRGB) { - result->background_color.ir = background->red; - result->background_color.ig = background->green; - result->background_color.ib = background->blue; - /* TODO: sometimes libpng uses the power law conversion here, how - * to handle this? - */ - result->background_color.dr = sRGB_to_d[background->red]; - result->background_color.dg = sRGB_to_d[background->green]; - result->background_color.db = sRGB_to_d[background->blue]; + error_limit = error_to_sRGB; + err = "linear to 8-bit gray conversion error"; } + } - else /* grayscale: libpng only looks at 'g' */ + if (a->format & PNG_FORMAT_FLAG_COLOR) + { + /* Converted to grayscale, allow drift */ + if (error_limit < error_to_sRGB_grayscale) { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = background->green; - /* TODO: sometimes libpng uses the power law conversion here, how - * to handle this? - */ - result->background_color.dr = - result->background_color.dg = - result->background_color.db = sRGB_to_d[background->green]; + error_limit = error_to_sRGB_grayscale; + err = "color to 8-bit gray conversion error"; } } - else if ((out_format & PNG_FORMAT_FLAG_COLORMAP) == 0) - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = BUFFER_INIT8; - /* TODO: sometimes libpng uses the power law conversion here, how - * to handle this? - */ - result->background_color.dr = - result->background_color.dg = - result->background_color.db = sRGB_to_d[BUFFER_INIT8]; - } + if (abs(a->y8-b->y8) <= error_limit) + return NULL; - /* Else the output is colormapped and a background color must be - * provided; if pngstest crashes then that is a bug in this program - * (though libpng should png_error as well.) - */ - else - result->background = NULL; + return err; } } - - if (result->background == NULL) - { - result->background_color.ir = - result->background_color.ig = - result->background_color.ib = -1; /* not used */ - result->background_color.dr = - result->background_color.dg = - result->background_color.db = 1E30; /* not used */ - } - - - /* Copy the error values into the Transform: */ - result->error[0] = result->error_ptr[0]; - result->error[1] = result->error_ptr[1]; - result->error[2] = result->error_ptr[2]; - result->error[3] = result->error_ptr[3]; } - -/* Compare two pixels. - * - * OLD error values: -static int error_to_linear = 811; * by experiment * -static int error_to_linear_grayscale = 424; * by experiment * -static int error_to_sRGB = 6; * by experiment * -static int error_to_sRGB_grayscale = 17; * libpng error by calculation + - 2 by experiment * -static int error_in_compose = 2; * by experiment * -static int error_in_premultiply = 1; - * - * The following is *just* the result of a round trip from 8-bit sRGB to linear - * then back to 8-bit sRGB when it is done by libpng. There are two problems: - * - * 1) libpng currently uses a 2.2 power law with no linear segment, this results - * in instability in the low values and even with 16-bit precision sRGB(1) ends - * up mapping to sRGB(0) as a result of rounding in the 16-bit representation. - * This gives an error of 1 in the handling of value 1 only. - * - * 2) libpng currently uses an intermediate 8-bit linear value in gamma - * correction of 8-bit values. This results in many more errors, the worse of - * which is mapping sRGB(14) to sRGB(0). - * - * The general 'error_via_linear' is more complex because of pre-multiplication, - * this compounds the 8-bit errors according to the alpha value of the pixel. - * As a result 256 values are pre-calculated for error_via_linear. - */ -#if 0 -static int error_in_libpng_gamma; -static int error_via_linear[256]; /* Indexed by 8-bit alpha */ - -static void -init_error_via_linear(void) -{ - int alpha; - - error_via_linear[0] = 255; /* transparent pixel */ - - for (alpha=1; alpha<=255; ++alpha) - { - /* 16-bit values less than 128.5 get rounded to 8-bit 0 and so the worst - * case error arises with 16-bit 128.5, work out what sRGB - * (non-associated) value generates 128.5; any value less than this is - * going to map to 0, so the worst error is floor(value). - * - * Note that errors are considerably higher (more than a factor of 2) - * because libpng uses a simple power law for sRGB data at present. - * - * Add .1 for arithmetic errors inside libpng. - */ - double v = floor(255*pow(.5/*(128.5 * 255 / 65535)*/ / alpha, 1/2.2)+.1); - - error_via_linear[alpha] = (int)v; - } - - /* This is actually 14.99, but, despite the closeness to 15, 14 seems to work - * ok in this case. - */ - error_in_libpng_gamma = 14; -} -#endif +/* Basic image formats; control the data but not the layout thereof. */ +#define BASE_FORMATS\ + (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_LINEAR) static void -print_pixel(char string[64], const Pixel *pixel, png_uint_32 format) +print_pixel(char string[64], Pixel *pixel) { - switch (format & (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR)) + switch (pixel->format & BASE_FORMATS) { - case 0: - sprintf(string, "%s(%d)", format_names[format], pixel->g); + case 0: /* 8-bit, one channel */ + sprintf(string, "%s(%d)", format_names[pixel->format], pixel->y8); break; case PNG_FORMAT_FLAG_ALPHA: - sprintf(string, "%s(%d,%d)", format_names[format], pixel->g, - pixel->a); + sprintf(string, "%s(%d,%d)", format_names[pixel->format], pixel->y8, + pixel->a8); break; case PNG_FORMAT_FLAG_COLOR: - sprintf(string, "%s(%d,%d,%d)", format_names[format], - pixel->r, pixel->g, pixel->b); + sprintf(string, "%s(%d,%d,%d)", format_names[pixel->format], + pixel->r8, pixel->g8, pixel->b8); break; case PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA: - sprintf(string, "%s(%d,%d,%d,%d)", format_names[format], - pixel->r, pixel->g, pixel->b, pixel->a); + sprintf(string, "%s(%d,%d,%d,%d)", format_names[pixel->format], + pixel->r8, pixel->g8, pixel->b8, pixel->a8); break; - default: - sprintf(string, "invalid-format"); + case PNG_FORMAT_FLAG_LINEAR: + sprintf(string, "%s(%d)", format_names[pixel->format], pixel->y16); break; - } -} - -static int -logpixel(const Transform *transform, png_uint_32 x, png_uint_32 y, - const Pixel *in, const Pixel *calc, const Pixel *out, const char *reason) -{ - const png_uint_32 in_format = transform->in_image->image.format; - const png_uint_32 out_format = transform->out_image->image.format; - - png_uint_32 back_format = out_format & ~PNG_FORMAT_FLAG_ALPHA; - const char *via_linear = ""; - - char pixel_in[64], pixel_calc[64], pixel_out[64], pixel_loc[64]; - char background_info[100]; - - print_pixel(pixel_in, in, in_format); - print_pixel(pixel_calc, calc, out_format); - print_pixel(pixel_out, out, out_format); - - if (transform->is_palette) - sprintf(pixel_loc, "palette: %lu", (unsigned long)y); - else - sprintf(pixel_loc, "%lu,%lu", (unsigned long)x, (unsigned long)y); - - if (transform->from_linear != NULL) - { - via_linear = " (via linear)"; - /* And as a result the *read* format which did any background processing - * was itself linear, so the background color information is also - * linear. - */ - back_format |= PNG_FORMAT_FLAG_LINEAR; - } - if (transform->background != NULL) - { - Pixel back; - char pixel_back[64]; - - back.r = transform->background->ir; - back.g = transform->background->ig; - back.b = transform->background->ib; - back.a = -1; /* not used */ - - print_pixel(pixel_back, &back, back_format); - sprintf(background_info, " on background %s", pixel_back); - } + case PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA: + sprintf(string, "%s(%d,%d)", format_names[pixel->format], pixel->y16, + pixel->a16); + break; - else - background_info[0] = 0; + case PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR: + sprintf(string, "%s(%d,%d,%d)", format_names[pixel->format], + pixel->r16, pixel->g16, pixel->b16); + break; - if (transform->in_image->file_name != transform->out_image->file_name) - { - char error_buffer[512]; - sprintf(error_buffer, - "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" - "Use --preserve and examine: ", pixel_loc, reason, via_linear, - pixel_in, background_info, pixel_out, pixel_calc); - return logerror(transform->in_image, transform->in_image->file_name, - error_buffer, transform->out_image->file_name); - } + case PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA: + sprintf(string, "%s(%d,%d,%d,%d)", format_names[pixel->format], + pixel->r16, pixel->g16, pixel->b16, pixel->a16); + break; - else - { - char error_buffer[512]; - sprintf(error_buffer, - "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" - " The error happened when reading the original file with this format.", - pixel_loc, reason, via_linear, pixel_in, background_info, pixel_out, - pixel_calc); - return logerror(transform->in_image, transform->in_image->file_name, - error_buffer, ""); + default: + sprintf(string, "invalid-format"); + break; } } static int -cmppixel(Transform *transform, png_const_voidp in, png_const_voidp out, - png_uint_32 x, png_uint_32 y/*or palette index*/) +logpixel(Image *image, png_uint_32 x, png_uint_32 y, Pixel *a, Pixel *b, + const char *reason) { - int maxerr; - png_const_charp errmsg; - Pixel pixel_in, pixel_calc, pixel_out; - - transform->in_gp(&pixel_in, in); - - if (transform->from_linear == NULL) - transform->transform(&pixel_calc, &pixel_in, transform->background); - - else - { - transform->transform(&pixel_out, &pixel_in, transform->background); - transform->from_linear(&pixel_calc, &pixel_out, NULL); - } - - transform->out_gp(&pixel_out, out); - - /* Eliminate the case where the input and output values match exactly. */ - if (pixel_calc.a == pixel_out.a && pixel_calc.r == pixel_out.r && - pixel_calc.g == pixel_out.g && pixel_calc.b == pixel_out.b) - return 1; - - /* Eliminate the case where the output pixel is transparent and the output - * is 8-bit - any component values are valid. Don't check the input alpha - * here to also skip the 16-bit small alpha cases. - */ - if (transform->output_8bit && pixel_calc.a == 0 && pixel_out.a == 0) - return 1; - - /* Check for alpha errors first; an alpha error can damage the components too - * so avoid spurious checks on components if one is found. - */ - errmsg = NULL; - { - int err_a = abs(pixel_calc.a-pixel_out.a); - - if (err_a > transform->error[3]) - { - /* If accumulating check the components too */ - if (transform->accumulate) - transform->error[3] = (png_uint_16)err_a; - - else - errmsg = "alpha"; - } - } + char pixel_a[64], pixel_b[64]; + char error_buffer[256]; - /* Now if *either* of the output alphas are 0 but alpha is within tolerance - * eliminate the 8-bit component comparison. - */ - if (errmsg == NULL && transform->output_8bit && - (pixel_calc.a == 0 || pixel_out.a == 0)) - return 1; - - if (errmsg == NULL) /* else just signal an alpha error */ - { - int err_r = abs(pixel_calc.r - pixel_out.r); - int err_g = abs(pixel_calc.g - pixel_out.g); - int err_b = abs(pixel_calc.b - pixel_out.b); - int limit; - - if ((err_r | err_g | err_b) == 0) - return 1; /* exact match */ - - /* Mismatch on a component, check the input alpha */ - if (pixel_in.a >= transform->in_opaque) - { - errmsg = "opaque component"; - limit = 2; /* opaque */ - } - - else if (pixel_in.a > 0) - { - errmsg = "alpha component"; - limit = 1; /* partially transparent */ - } - - else - { - errmsg = "transparent component (background)"; - limit = 0; /* transparent */ - } - - maxerr = err_r; - if (maxerr < err_g) maxerr = err_g; - if (maxerr < err_b) maxerr = err_b; - - if (maxerr <= transform->error[limit]) - return 1; /* within the error limits */ - - /* Handle a component mis-match; log it, just return an error code, or - * accumulate it. - */ - if (transform->accumulate) - { - transform->error[limit] = (png_uint_16)maxerr; - return 1; /* to cause the caller to keep going */ - } - } - - /* Failure to match and not accumulating, so the error must be logged. */ - return logpixel(transform, x, y, &pixel_in, &pixel_calc, &pixel_out, errmsg); -} - -static png_byte -component_loc(png_byte loc[4], png_uint_32 format) -{ - /* Given a format return the number of channels and the location of - * each channel. - * - * The mask 'loc' contains the component offset of the channels in the - * following order. Note that if 'format' is grayscale the entries 1-3 must - * all contain the location of the gray channel. - * - * 0: alpha - * 1: red or gray - * 2: green or gray - * 3: blue or gray - */ - png_byte channels; - - if (format & PNG_FORMAT_FLAG_COLOR) - { - channels = 3; - - loc[2] = 1; - - if (format & PNG_FORMAT_FLAG_BGR) - { - loc[1] = 2; - loc[3] = 0; - } - - else - { - loc[1] = 0; - loc[3] = 2; - } - } - - else - { - channels = 1; - loc[1] = loc[2] = loc[3] = 0; - } - - if (format & PNG_FORMAT_FLAG_ALPHA) - { - if (format & PNG_FORMAT_FLAG_AFIRST) - { - loc[0] = 0; - ++loc[1]; - ++loc[2]; - ++loc[3]; - } - - else - loc[0] = channels; - - ++channels; - } - - else - loc[0] = 4; /* not present */ - - return channels; + print_pixel(pixel_a, a); + print_pixel(pixel_b, b); + sprintf(error_buffer, "(%lu,%lu) %s: %s -> %s", (unsigned long)x, + (unsigned long)y, reason, pixel_a, pixel_b); + return logerror(image, image->file_name, error_buffer, ""); } /* Compare two images, the original 'a', which was written out then read back in * to * give image 'b'. The formats may have been changed. */ static int -compare_two_images(Image *a, Image *b, int via_linear, - png_const_colorp background) +compare_two_images(Image *a, Image *b, int via_linear) { + png_uint_32 width = a->image.width; + png_uint_32 height = a->image.height; + png_uint_32 formata = a->image.format; + png_uint_32 formatb = b->image.format; ptrdiff_t stridea = a->stride; ptrdiff_t strideb = b->stride; png_const_bytep rowa = a->buffer+16; png_const_bytep rowb = b->buffer+16; - const png_uint_32 width = a->image.width; - const png_uint_32 height = a->image.height; - const png_uint_32 formata = a->image.format; - const png_uint_32 formatb = b->image.format; - const unsigned int a_sample = PNG_IMAGE_SAMPLE_SIZE(formata); - const unsigned int b_sample = PNG_IMAGE_SAMPLE_SIZE(formatb); - int alpha_added, alpha_removed; - int bchannels; - int btoa[4]; - png_uint_32 y; - Transform tr; + png_byte channels; + int linear = 0; + int result = 1; + unsigned int check_alpha = 0; /* must be zero or one */ + png_byte swap_mask[4]; + png_uint_32 x, y; + png_const_bytep ppa, ppb; + const png_color *background = + ((a->opts & USE_BACKGROUND) ? &a->background : NULL); /* This should never happen: */ if (width != b->image.width || height != b->image.height) return logerror(a, a->file_name, ": width x height changed: ", b->file_name); - /* Set up the background and the transform */ - transform_from_formats(&tr, a, b, background, via_linear); - /* Find the first row and inter-row space. */ - if (!(formata & PNG_FORMAT_FLAG_COLORMAP) && - (formata & PNG_FORMAT_FLAG_LINEAR)) - stridea *= 2; + if (formata & PNG_FORMAT_FLAG_LINEAR) + { + stridea *= sizeof (png_uint_16); + ++linear; + } - if (!(formatb & PNG_FORMAT_FLAG_COLORMAP) && - (formatb & PNG_FORMAT_FLAG_LINEAR)) - strideb *= 2; + if (formatb & PNG_FORMAT_FLAG_LINEAR) + { + strideb *= sizeof (png_uint_16); + ++linear; + } if (stridea < 0) rowa += (height-1) * (-stridea); if (strideb < 0) rowb += (height-1) * (-strideb); - /* First shortcut the two colormap case by comparing the image data; if it - * matches then we expect the colormaps to match, although this is not - * absolutely necessary for an image match. If the colormaps fail to match - * then there is a problem in libpng. + /* The following are used only if the formats match, except that 'channels' + * is a flag for matching formats. */ - if (formata & formatb & PNG_FORMAT_FLAG_COLORMAP) - { - /* Only check colormap entries that actually exist; */ - png_const_bytep ppa, ppb; - int match; - png_byte in_use[256], amax = 0, bmax = 0; - - memset(in_use, 0, sizeof in_use); - - ppa = rowa; - ppb = rowb; + channels = 0; + swap_mask[3] = swap_mask[2] = swap_mask[1] = swap_mask[0] = 0; - /* Do this the slow way to accumulate the 'in_use' flags, don't break out - * of the loop until the end; this validates the color-mapped data to - * ensure all pixels are valid color-map indexes. - */ - for (y=0, match=1; y<height && match; ++y, ppa += stridea, ppb += strideb) - { - png_uint_32 x; - - for (x=0; x<width; ++x) - { - png_byte bval = ppb[x]; - png_byte aval = ppa[x]; - - if (bval > bmax) - bmax = bval; - - if (bval != aval) - match = 0; + /* Set up the masks if no base format change, or if the format change was + * just to add an alpha channel. + */ + if (((formata | PNG_FORMAT_FLAG_ALPHA) & BASE_FORMATS) == + (formatb & BASE_FORMATS)) + { + png_byte astart = 0; /* index of first component */ + png_byte bstart = 0; - in_use[aval] = 1; - if (aval > amax) - amax = aval; - } - } + /* Set to the actual number of channels in 'a' */ + channels = (formata & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; - /* If the buffers match then the colormaps must too. */ - if (match) + if (formata & PNG_FORMAT_FLAG_ALPHA) { - /* Do the color-maps match, entry by entry? Only check the 'in_use' - * entries. An error here should be logged as a color-map error. - */ - png_const_bytep a_cmap = (png_const_bytep)a->colormap; - png_const_bytep b_cmap = (png_const_bytep)b->colormap; - int result = 1; /* match by default */ - - /* This is used in logpixel to get the error message correct. */ - tr.is_palette = 1; - - for (y=0; y<256; ++y, a_cmap += a_sample, b_cmap += b_sample) - if (in_use[y]) + /* Both formats have an alpha channel */ + if (formata & PNG_FORMAT_FLAG_AFIRST) { - /* The colormap entries should be valid, but because libpng doesn't - * do any checking at present the original image may contain invalid - * pixel values. These cause an error here (at present) unless - * accumulating errors in which case the program just ignores them. - */ - if (y >= a->image.colormap_entries) - { - if ((a->opts & ACCUMULATE) == 0) - { - char pindex[9]; - sprintf(pindex, "%lu[%lu]", (unsigned long)y, - (unsigned long)a->image.colormap_entries); - logerror(a, a->file_name, ": bad pixel index: ", pindex); - } - result = 0; - } + astart = 1; - else if (y >= b->image.colormap_entries) + if (formatb & PNG_FORMAT_FLAG_AFIRST) { - if ((a->opts & ACCUMULATE) == 0) - { - char pindex[9]; - sprintf(pindex, "%lu[%lu]", (unsigned long)y, - (unsigned long)b->image.colormap_entries); - logerror(b, b->file_name, ": bad pixel index: ", pindex); - } - result = 0; + bstart = 1; + swap_mask[0] = 0; } - /* All the mismatches are logged here; there can only be 256! */ - else if (!cmppixel(&tr, a_cmap, b_cmap, 0, y)) - result = 0; + else + swap_mask[0] = channels; /* 'b' alpha is at end */ } - /* If reqested copy the error values back from the Transform. */ - if (a->opts & ACCUMULATE) + else if (formatb & PNG_FORMAT_FLAG_AFIRST) { - tr.error_ptr[0] = tr.error[0]; - tr.error_ptr[1] = tr.error[1]; - tr.error_ptr[2] = tr.error[2]; - tr.error_ptr[3] = tr.error[3]; - result = 1; /* force a continue */ + /* 'a' alpha is at end, 'b' is at start (0) */ + bstart = 1; + swap_mask[channels] = 0; } - return result; + else + swap_mask[channels] = channels; + + ++channels; } - /* else the image buffers don't match pixel-wise so compare sample values - * instead, but first validate that the pixel indexes are in range (but - * only if not accumulating, when the error is ignored.) - */ - else if ((a->opts & ACCUMULATE) == 0) + else if (formatb & PNG_FORMAT_FLAG_ALPHA) { - /* Check the original image first, - * TODO: deal with input images with bad pixel values? - */ - if (amax >= a->image.colormap_entries) + /* Only 'b' has an alpha channel */ + check_alpha = 1; + if (formatb & PNG_FORMAT_FLAG_AFIRST) { - char pindex[9]; - sprintf(pindex, "%d[%lu]", amax, - (unsigned long)a->image.colormap_entries); - return logerror(a, a->file_name, ": bad pixel index: ", pindex); + bstart = 1; + /* Put the location of the alpha channel in swap_mask[3], since it + * cannot be used if 'a' does not have an alpha channel. + */ + swap_mask[3] = 0; } - else if (bmax >= b->image.colormap_entries) - { - char pindex[9]; - sprintf(pindex, "%d[%lu]", bmax, - (unsigned long)b->image.colormap_entries); - return logerror(b, b->file_name, ": bad pixel index: ", pindex); - } + else + swap_mask[3] = channels; } - } - - /* We can directly compare pixel values without the need to use the read - * or transform support (i.e. a memory compare) if: - * - * 1) The bit depth has not changed. - * 2) RGB to grayscale has not been done (the reverse is ok; we just compare - * the three RGB values to the original grayscale.) - * 3) An alpha channel has not been removed from an 8-bit format, or the - * 8-bit alpha value of the pixel was 255 (opaque). - * - * If an alpha channel has been *added* then it must have the relevant opaque - * value (255 or 65535). - * - * The fist two the tests (in the order given above) (using the boolean - * equivalence !a && !b == !(a || b)) - */ - if (!(((formata ^ formatb) & PNG_FORMAT_FLAG_LINEAR) | - (formata & (formatb ^ PNG_FORMAT_FLAG_COLOR) & PNG_FORMAT_FLAG_COLOR))) - { - /* Was an alpha channel changed? */ - const png_uint_32 alpha_changed = (formata ^ formatb) & - PNG_FORMAT_FLAG_ALPHA; - /* Was an alpha channel removed? (The third test.) If so the direct - * comparison is only possible if the input alpha is opaque. - */ - alpha_removed = (formata & alpha_changed) != 0; - - /* Was an alpha channel added? */ - alpha_added = (formatb & alpha_changed) != 0; - - /* The channels may have been moved between input and output, this finds - * out how, recording the result in the btoa array, which says where in - * 'a' to find each channel of 'b'. If alpha was added then btoa[alpha] - * ends up as 4 (and is not used.) - */ + if (formata & PNG_FORMAT_FLAG_COLOR) { - int i; - png_byte aloc[4]; - png_byte bloc[4]; - - /* The following are used only if the formats match, except that - * 'bchannels' is a flag for matching formats. btoa[x] says, for each - * channel in b, where to find the corresponding value in a, for the - * bchannels. achannels may be different for a gray to rgb transform - * (a will be 1 or 2, b will be 3 or 4 channels.) - */ - (void)component_loc(aloc, formata); - bchannels = component_loc(bloc, formatb); - - /* Hence the btoa array. */ - for (i=0; i<4; ++i) if (bloc[i] < 4) - btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */ - - if (alpha_added) - alpha_added = bloc[0]; /* location of alpha channel in image b */ - - else - alpha_added = 4; /* Won't match an image b channel */ + unsigned int swap = 0; - if (alpha_removed) - alpha_removed = aloc[0]; /* location of alpha channel in image a */ + /* Colors match, but are they swapped? */ + if ((formata ^ formatb) & PNG_FORMAT_FLAG_BGR) /* Swapped. */ + swap = 2; - else - alpha_removed = 4; + swap_mask[astart+0] = (png_byte)(bstart+(0^swap)); + swap_mask[astart+1] = (png_byte)(bstart+1); + swap_mask[astart+2] = (png_byte)(bstart+(2^swap)); } - } - else - { - /* Direct compare is not possible, cancel out all the corresponding local - * variables. - */ - bchannels = 0; - alpha_removed = alpha_added = 4; - btoa[3] = btoa[2] = btoa[1] = btoa[0] = 4; /* 4 == not present */ + else /* grayscale: 1 channel */ + swap_mask[astart] = bstart; } - for (y=0; y<height; ++y, rowa += stridea, rowb += strideb) + ppa = rowa; + ppb = rowb; + for (x=y=0; y<height;) { - png_const_bytep ppa, ppb; - png_uint_32 x; - - for (x=0, ppa=rowa, ppb=rowb; x<width; ++x) + /* Do the fast test if possible. */ + if (channels != 0) switch (linear) { - png_const_bytep psa, psb; - - if (formata & PNG_FORMAT_FLAG_COLORMAP) - psa = (png_const_bytep)a->colormap + a_sample * *ppa++; - else - psa = ppa, ppa += a_sample; - - if (formatb & PNG_FORMAT_FLAG_COLORMAP) - psb = (png_const_bytep)b->colormap + b_sample * *ppb++; - else - psb = ppb, ppb += b_sample; - - /* Do the fast test if possible. */ - if (bchannels) - { - /* Check each 'b' channel against either the corresponding 'a' - * channel or the opaque alpha value, as appropriate. If - * alpha_removed value is set (not 4) then also do this only if the - * 'a' alpha channel (alpha_removed) is opaque; only relevant for - * the 8-bit case. - */ - if (formatb & PNG_FORMAT_FLAG_LINEAR) /* 16-bit checks */ + case 2: /* both sides linear */ { - png_const_uint_16p pua = aligncastconst(png_const_uint_16p, psa); - png_const_uint_16p pub = aligncastconst(png_const_uint_16p, psb); + png_const_uint_16p lppa = (png_const_uint_16p)ppa; + png_const_uint_16p lppb = (png_const_uint_16p)ppb; - switch (bchannels) + while (x < width) switch (channels) { case 4: - if (pua[btoa[3]] != pub[3]) break; + if (lppa[3] != lppb[swap_mask[3]]) + goto linear_mismatch; case 3: - if (pua[btoa[2]] != pub[2]) break; + if (lppa[2] != lppb[swap_mask[2]]) + goto linear_mismatch; case 2: - if (pua[btoa[1]] != pub[1]) break; + if (lppa[1] != lppb[swap_mask[1]]) + goto linear_mismatch; case 1: - if (pua[btoa[0]] != pub[0]) break; - if (alpha_added != 4 && pub[alpha_added] != 65535) break; - continue; /* x loop */ + if (lppa[0] != lppb[swap_mask[0]]) + goto linear_mismatch; + + /* The pixels apparently match, but if an alpha channel has + * been added (in b) it must be 65535 too. + */ + if (check_alpha && 65535 != lppb[swap_mask[3]]) + goto linear_mismatch; + + /* This pixel matches, advance to the next. */ + lppa += channels; + lppb += channels + check_alpha; + ++x; default: - break; /* impossible */ + break; } + + linear_mismatch: + ppa = (png_const_bytep)lppa; + ppb = (png_const_bytep)lppb; } + break; - else if (alpha_removed == 4 || psa[alpha_removed] == 255) + case 0: /* both sides sRGB */ + while (x < width) switch (channels) { - switch (bchannels) - { - case 4: - if (psa[btoa[3]] != psb[3]) break; - case 3: - if (psa[btoa[2]] != psb[2]) break; - case 2: - if (psa[btoa[1]] != psb[1]) break; - case 1: - if (psa[btoa[0]] != psb[0]) break; - if (alpha_added != 4 && psb[alpha_added] != 255) break; - continue; /* x loop */ - default: - break; /* impossible */ - } + case 4: + if (ppa[3] != ppb[swap_mask[3]]) + goto sRGB_mismatch; + case 3: + if (ppa[2] != ppb[swap_mask[2]]) + goto sRGB_mismatch; + case 2: + if (ppa[1] != ppb[swap_mask[1]]) + goto sRGB_mismatch; + case 1: + if (ppa[0] != ppb[swap_mask[0]]) + goto sRGB_mismatch; + + /* The pixels apparently match, but if an alpha channel has + * been added (in b) it must be 1.0 too. + */ + if (check_alpha && 255 != ppb[swap_mask[3]]) + goto sRGB_mismatch; + + /* This pixel matches, advance to the next. */ + ppa += channels; + ppb += channels + check_alpha; + ++x; + default: + break; } + + sRGB_mismatch: + break; + + default: /* formats do not match */ + break; + } + + /* If at the end of the row advance to the next row, if not at the end + * compare the pixels the slow way. + */ + if (x < width) + { + Pixel pixel_a, pixel_b; + const char *mismatch; + + get_pixel(a, &pixel_a, ppa); + get_pixel(b, &pixel_b, ppb); + mismatch = cmppixel(&pixel_a, &pixel_b, background, via_linear); + + if (mismatch != NULL) + { + (void)logpixel(a, x, y, &pixel_a, &pixel_b, mismatch); + + if ((a->opts & KEEP_GOING) == 0) + return 0; + + result = 0; } - /* If we get to here the fast match failed; do the slow match for this - * pixel. - */ - if (!cmppixel(&tr, psa, psb, x, y) && (a->opts & KEEP_GOING) == 0) - return 0; /* error case */ + ++x; } - } - /* If reqested copy the error values back from the Transform. */ - if (a->opts & ACCUMULATE) - { - tr.error_ptr[0] = tr.error[0]; - tr.error_ptr[1] = tr.error[1]; - tr.error_ptr[2] = tr.error[2]; - tr.error_ptr[3] = tr.error[3]; + if (x >= width) + { + x = 0; + ++y; + rowa += stridea; + rowb += strideb; + ppa = rowa; + ppb = rowb; + } } - return 1; + return result; } /* Read the file; how the read gets done depends on which of input_file and * input_memory have been set. */ static int -read_file(Image *image, png_uint_32 format, png_const_colorp background) +read_file(Image *image, png_uint_32 format) { - memset(&image->image, 0, sizeof image->image); - image->image.version = PNG_IMAGE_VERSION; - if (image->input_memory != NULL) { if (!png_image_begin_read_from_memory(&image->image, image->input_memory, @@ -3031,50 +1303,30 @@ read_file(Image *image, png_uint_32 format, png_const_colorp background) */ { int result; - png_uint_32 image_format; - /* Print both original and output formats. */ - image_format = image->image.format; + /* Various random settings for detecting overwrites */ + image->background.red = 89; + image->background.green = 78; + image->background.blue = 178; + /* Print both original and output formats. */ if (image->opts & VERBOSE) - { - printf("%s %lu x %lu %s -> %s", image->file_name, + printf("%s %lu x %lu %s -> %s\n", image->file_name, (unsigned long)image->image.width, (unsigned long)image->image.height, - format_names[image_format & FORMAT_MASK], + format_names[image->image.format & 0x1f], (format & FORMAT_NO_CHANGE) != 0 || image->image.format == format - ? "no change" : format_names[format & FORMAT_MASK]); + ? "no change" : format_names[format & 0x1f]); - if (background != NULL) - printf(" background(%d,%d,%d)\n", background->red, - background->green, background->blue); - else - printf("\n"); - - fflush(stdout); - } - - /* 'NO_CHANGE' combined with the color-map flag forces the base format - * flags to be set on read to ensure that the original representation is - * not lost in the pass through a colormap format. - */ - if ((format & FORMAT_NO_CHANGE) != 0) - { - if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && - (image_format & PNG_FORMAT_FLAG_COLORMAP) != 0) - format = (image_format & ~BASE_FORMATS) | (format & BASE_FORMATS); - - else - format = image_format; - } - - image->image.format = format; + if ((format & FORMAT_NO_CHANGE) == 0) + image->image.format = format; image->stride = PNG_IMAGE_ROW_STRIDE(image->image) + image->stride_extra; allocbuffer(image); - result = png_image_finish_read(&image->image, background, - image->buffer+16, (png_int_32)image->stride, image->colormap); + result = png_image_finish_read(&image->image, + (image->opts & USE_BACKGROUND) ? &image->background : NULL, + image->buffer+16, (png_int_32)image->stride); checkbuffer(image, image->file_name); @@ -3087,11 +1339,10 @@ read_file(Image *image, png_uint_32 format, png_const_colorp background) } /* Reads from a filename, which must be in image->file_name, but uses - * image->opts to choose the method. The file is always read in its native - * format (the one the simplified API suggests). + * image->opts to choose the method. */ static int -read_one_file(Image *image) +read_one_file(Image *image, png_uint_32 format) { if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO)) { @@ -3109,7 +1360,7 @@ read_one_file(Image *image) { long int cb = ftell(f); - if (cb > 0 && (unsigned long int)cb < (size_t)~(size_t)0) + if (cb >= 0 && (unsigned long int)cb < (size_t)~(size_t)0) { png_bytep b = voidcast(png_bytep, malloc((size_t)cb)); @@ -3128,22 +1379,17 @@ read_one_file(Image *image) { free(b); return logclose(image, f, image->file_name, - ": read failed: "); + ": read failed"); } } else return logclose(image, f, image->file_name, - ": out of memory: "); + ": out of memory"); } - else if (cb == 0) - return logclose(image, f, image->file_name, - ": zero length: "); - else - return logclose(image, f, image->file_name, - ": tell failed: "); + return logclose(image, f, image->file_name, ": tell failed"); } else @@ -3156,16 +1402,12 @@ read_one_file(Image *image) strerror(errno)); } - return read_file(image, FORMAT_NO_CHANGE, NULL); + return read_file(image, format); } -#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED static int write_one_file(Image *output, Image *image, int convert_to_8bit) { - if (image->opts & FAST_WRITE) - image->image.flags |= PNG_IMAGE_FLAG_FAST; - if (image->opts & USE_STDIO) { FILE *f = tmpfile(); @@ -3173,7 +1415,7 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) if (f != NULL) { if (png_image_write_to_stdio(&image->image, f, convert_to_8bit, - image->buffer+16, (png_int_32)image->stride, image->colormap)) + image->buffer+16, (png_int_32)image->stride)) { if (fflush(f) == 0) { @@ -3185,7 +1427,7 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) } else - return logclose(image, f, "tmpfile", ": flush: "); + return logclose(image, f, "tmpfile", ": flush"); } else @@ -3204,10 +1446,10 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) static int counter = 0; char name[32]; - sprintf(name, "%s%d.png", tmpf, ++counter); + sprintf(name, "TMP%d.png", ++counter); if (png_image_write_to_file(&image->image, name, convert_to_8bit, - image->buffer+16, (png_int_32)image->stride, image->colormap)) + image->buffer+16, (png_int_32)image->stride)) { initimage(output, image->opts, output->tmpfile_name, image->stride_extra); @@ -3225,33 +1467,25 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) /* 'output' has an initialized temporary image, read this back in and compare * this against the original: there should be no change since the original * format was written unmodified unless 'convert_to_8bit' was specified. - * However, if the original image was color-mapped, a simple read will zap - * the linear, color and maybe alpha flags, this will cause spurious failures - * under some circumstances. */ - if (read_file(output, image->image.format | FORMAT_NO_CHANGE, NULL)) + if (read_file(output, FORMAT_NO_CHANGE)) { - png_uint_32 original_format = image->image.format; - - if (convert_to_8bit) - original_format &= ~PNG_FORMAT_FLAG_LINEAR; - if ((output->image.format & BASE_FORMATS) != - (original_format & BASE_FORMATS)) - return logerror(image, image->file_name, ": format changed on read: ", + ((image->image.format & BASE_FORMATS) & + ~(convert_to_8bit ? PNG_FORMAT_FLAG_LINEAR : 0))) + return logerror(image, image->file_name, ": format changed on read:", output->file_name); - return compare_two_images(image, output, 0/*via linear*/, NULL); + return compare_two_images(image, output, 0); } else return logerror(output, output->tmpfile_name, ": read of new file failed", ""); } -#endif static int -testimage(Image *image, png_uint_32 opts, format_list *pf) +testimage(Image *image, png_uint_32 opts, png_uint_32 formats) { int result; Image copy; @@ -3271,113 +1505,56 @@ testimage(Image *image, png_uint_32 opts, format_list *pf) image->tmpfile_name[0] = 0; { - png_uint_32 counter; + png_uint_32 format; Image output; newimage(&output); - + result = 1; - - /* Use the low bit of 'counter' to indicate whether or not to do alpha - * removal with a background color or by composting onto the image; this - * step gets skipped if it isn't relevant - */ - for (counter=0; counter<2*FORMAT_COUNT; ++counter) - if (format_isset(pf, counter >> 1)) + for (format=0; format<32; ++format) if (formats & (1<<format)) { - png_uint_32 format = counter >> 1; + resetimage(©); + result = read_file(©, format); + if (!result) + break; - png_color background_color; - png_colorp background = NULL; + /* Make sure the file just read matches the original file. */ + result = compare_two_images(image, ©, 0); + if (!result) + break; - /* If there is a format change that removes the alpha channel then - * the background is relevant. If the output is 8-bit color-mapped - * then a background color *must* be provided, otherwise there are - * two tests to do - one with a color, the other with NULL. The - * NULL test happens second. + /* Write the *copy* just made to a new file to make sure the write side + * works ok. Check the conversion to sRGB if the copy is linear. */ - if ((counter & 1) == 0) - { - if ((format & PNG_FORMAT_FLAG_ALPHA) == 0 && - (image->image.format & PNG_FORMAT_FLAG_ALPHA) != 0) - { - /* Alpha/transparency will be removed, the background is - * relevant: make it a color the first time - */ - random_color(&background_color); - background = &background_color; - - /* BUT if the output is to a color-mapped 8-bit format then - * the background must always be a color, so increment 'counter' - * to skip the NULL test. - */ - if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && - (format & PNG_FORMAT_FLAG_LINEAR) == 0) - ++counter; - } - - /* Otherwise an alpha channel is not being eliminated, just leave - * background NULL and skip the (counter & 1) NULL test. - */ - else - ++counter; - } - /* else just use NULL for background */ - - resetimage(©); - copy.opts = opts; /* in case read_file needs to change it */ - - result = read_file(©, format, background); + result = write_one_file(&output, ©, 0/*convert to 8bit*/); if (!result) break; - /* Make sure the file just read matches the original file. */ - result = compare_two_images(image, ©, 0/*via linear*/, background); + /* Validate against the original too: */ + result = compare_two_images(image, &output, 0); if (!result) break; -# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED - /* Write the *copy* just made to a new file to make sure the write - * side works ok. Check the conversion to sRGB if the copy is - * linear. - */ - output.opts = opts; - result = write_one_file(&output, ©, 0/*convert to 8bit*/); + if ((output.image.format & PNG_FORMAT_FLAG_LINEAR) != 0) + { + /* 'output' is linear, convert to the corresponding sRGB format. */ + result = write_one_file(&output, ©, 1/*convert to 8bit*/); if (!result) break; - /* Validate against the original too; the background is needed here - * as well so that compare_two_images knows what color was used. + /* This may involve a conversion via linear; in the ideal world this + * would round-trip correctly, but libpng 1.5.7 is not the ideal + * world so allow a drift (error_via_linear). + * + * 'image' has an alpha channel but 'output' does not then there + * will a strip-alpha-channel operation (because 'output' is + * linear), handle this by composing on black when doing the + * comparison. */ - result = compare_two_images(image, &output, 0, background); + result = compare_two_images(image, &output, 1/*via_linear*/); if (!result) break; - - if ((format & PNG_FORMAT_FLAG_LINEAR) != 0 && - (format & PNG_FORMAT_FLAG_COLORMAP) == 0) - { - /* 'output' is linear, convert to the corresponding sRGB format. - */ - output.opts = opts; - result = write_one_file(&output, ©, 1/*convert to 8bit*/); - if (!result) - break; - - /* This may involve a conversion via linear; in the ideal world - * this would round-trip correctly, but libpng 1.5.7 is not the - * ideal world so allow a drift (error_via_linear). - * - * 'image' has an alpha channel but 'output' does not then there - * will a strip-alpha-channel operation (because 'output' is - * linear), handle this by composing on black when doing the - * comparison. - */ - result = compare_two_images(image, &output, 1/*via_linear*/, - background); - if (!result) - break; - } -# endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ + } } freeimage(&output); @@ -3388,76 +1565,23 @@ testimage(Image *image, png_uint_32 opts, format_list *pf) return result; } -static int -test_one_file(const char *file_name, format_list *formats, png_uint_32 opts, - int stride_extra, int log_pass) -{ - int result; - Image image; - - newimage(&image); - initimage(&image, opts, file_name, stride_extra); - result = read_one_file(&image); - if (result) - result = testimage(&image, opts, formats); - freeimage(&image); - - /* Ensure that stderr is flushed into any log file */ - fflush(stderr); - - if (log_pass) - { - if (result) - printf("PASS:"); - - else - printf("FAIL:"); - -# ifndef PNG_SIMPLIFIED_WRITE_SUPPORTED - printf(" (no write)"); -# endif - - print_opts(opts); - printf(" %s\n", file_name); - /* stdout may not be line-buffered if it is piped to a file, so: */ - fflush(stdout); - } - - else if (!result) - exit(1); - - return result; -} - int -main(int argc, char **argv) +main(int argc, const char **argv) { - png_uint_32 opts = FAST_WRITE; - format_list formats; + png_uint_32 opts = 0; + png_uint_32 formats = (png_uint_32)~0; /* a mask of formats to test */ const char *touch = NULL; int log_pass = 0; - int redundant = 0; int stride_extra = 0; int retval = 0; int c; - init_sRGB_to_d(); -#if 0 - init_error_via_linear(); -#endif - format_init(&formats); - for (c=1; c<argc; ++c) { const char *arg = argv[c]; if (strcmp(arg, "--log") == 0) log_pass = 1; - else if (strcmp(arg, "--fresh") == 0) - { - memset(gpc_error, 0, sizeof gpc_error); - memset(gpc_error_via_linear, 0, sizeof gpc_error_via_linear); - } else if (strcmp(arg, "--file") == 0) opts |= READ_FILE; else if (strcmp(arg, "--memory") == 0) @@ -3466,6 +1590,10 @@ main(int argc, char **argv) opts |= USE_STDIO; else if (strcmp(arg, "--name") == 0) opts &= ~USE_STDIO; + else if (strcmp(arg, "--background") == 0) + opts |= USE_BACKGROUND; + else if (strcmp(arg, "--composite") == 0) + opts &= ~USE_BACKGROUND; else if (strcmp(arg, "--verbose") == 0) opts |= VERBOSE; else if (strcmp(arg, "--quiet") == 0) @@ -3476,42 +1604,8 @@ main(int argc, char **argv) opts &= ~KEEP_TMPFILES; else if (strcmp(arg, "--keep-going") == 0) opts |= KEEP_GOING; - else if (strcmp(arg, "--fast") == 0) - opts |= FAST_WRITE; - else if (strcmp(arg, "--slow") == 0) - opts &= ~FAST_WRITE; - else if (strcmp(arg, "--accumulate") == 0) - opts |= ACCUMULATE; - else if (strcmp(arg, "--redundant") == 0) - redundant = 1; else if (strcmp(arg, "--stop") == 0) opts &= ~KEEP_GOING; - else if (strcmp(arg, "--strict") == 0) - opts |= STRICT; - else if (strcmp(arg, "--tmpfile") == 0) - { - if (c+1 < argc) - { - if (strlen(argv[++c]) >= sizeof tmpf) - { - fflush(stdout); - fprintf(stderr, "%s: %s is too long for a temp file prefix\n", - argv[0], argv[c]); - exit(99); - } - - /* Safe: checked above */ - strcpy(tmpf, argv[c]); - } - - else - { - fflush(stdout); - fprintf(stderr, "%s: %s requires a temporary file prefix\n", - argv[0], arg); - exit(99); - } - } else if (strcmp(arg, "--touch") == 0) { if (c+1 < argc) @@ -3519,176 +1613,58 @@ main(int argc, char **argv) else { - fflush(stdout); fprintf(stderr, "%s: %s requires a file name argument\n", argv[0], arg); - exit(99); + exit(1); } } else if (arg[0] == '+') { png_uint_32 format = formatof(arg+1); - if (format > FORMAT_COUNT) - exit(99); + if (format > 31) + exit(1); + + if (formats == (png_uint_32)~0) + formats = 0; - format_set(&formats, format); + formats |= 1<<format; } - else if (arg[0] == '-' && arg[1] != 0 && (arg[1] != '0' || arg[2] != 0)) + else if (arg[0] == '-') { - fflush(stdout); fprintf(stderr, "%s: unknown option: %s\n", argv[0], arg); - exit(99); + exit(1); } else { - if (format_is_initial(&formats)) - format_default(&formats, redundant); - - if (arg[0] == '-') - { - const int term = (arg[1] == '0' ? 0 : '\n'); - unsigned int ich = 0; - - /* Loop reading files, use a static buffer to simplify this and just - * stop if the name gets to long. - */ - static char buffer[4096]; - - do - { - int ch = getchar(); + int result; + Image image; - /* Don't allow '\0' in file names, and terminate with '\n' or, - * for -0, just '\0' (use -print0 to find to make this work!) - */ - if (ch == EOF || ch == term || ch == 0) - { - buffer[ich] = 0; - - if (ich > 0 && !test_one_file(buffer, &formats, opts, - stride_extra, log_pass)) - retval = 1; - - if (ch == EOF) - break; - - ich = 0; - --ich; /* so that the increment below sets it to 0 again */ - } - - else - buffer[ich] = (char)ch; - } while (++ich < sizeof buffer); + newimage(&image); + initimage(&image, opts, arg, stride_extra); + result = read_one_file(&image, FORMAT_NO_CHANGE); + if (result) + result = testimage(&image, opts, formats); + freeimage(&image); - if (ich) - { - buffer[32] = 0; - buffer[4095] = 0; - fprintf(stderr, "%s...%s: file name too long\n", buffer, - buffer+(4096-32)); - exit(99); - } - } - - else if (!test_one_file(arg, &formats, opts, stride_extra, log_pass)) - retval = 1; - } - } - - if (opts & ACCUMULATE) - { - unsigned int in; - - printf("static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =\n"); - printf("{\n"); - for (in=0; in<16; ++in) - { - unsigned int out; - printf(" { /* input: %s */\n ", format_names[in]); - for (out=0; out<16; ++out) + if (log_pass) { - unsigned int alpha; - printf(" {"); - for (alpha=0; alpha<4; ++alpha) - { - printf(" %d", gpc_error[in][out][alpha]); - if (alpha < 3) putchar(','); - } - printf(" }"); - if (out < 15) - { - putchar(','); - if (out % 4 == 3) printf("\n "); - } - } - printf("\n }"); - - if (in < 15) - putchar(','); - else - putchar('\n'); - } - printf("};\n"); + if (result) + printf("PASS:"); - printf("static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =\n"); - printf("{\n"); - for (in=0; in<16; ++in) - { - unsigned int out; - printf(" { /* input: %s */\n ", format_names[in]); - for (out=0; out<4; ++out) - { - unsigned int alpha; - printf(" {"); - for (alpha=0; alpha<4; ++alpha) + else { - printf(" %d", gpc_error_via_linear[in][out][alpha]); - if (alpha < 3) putchar(','); + printf("FAIL:"); + retval = 1; } - printf(" }"); - if (out < 3) - putchar(','); - } - printf("\n }"); - if (in < 15) - putchar(','); - else - putchar('\n'); - } - printf("};\n"); - - printf("static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =\n"); - printf("{\n"); - for (in=0; in<8; ++in) - { - unsigned int out; - printf(" { /* input: %s */\n ", format_names[in]); - for (out=0; out<8; ++out) - { - unsigned int alpha; - printf(" {"); - for (alpha=0; alpha<4; ++alpha) - { - printf(" %d", gpc_error_to_colormap[in][out][alpha]); - if (alpha < 3) putchar(','); - } - printf(" }"); - if (out < 7) - { - putchar(','); - if (out % 4 == 3) printf("\n "); - } + print_opts(opts); + printf(" %s\n", arg); } - printf("\n }"); - if (in < 7) - putchar(','); - else - putchar('\n'); + else if (!result) + exit(1); } - printf("};\n"); } if (retval == 0 && touch != NULL) @@ -3704,28 +1680,17 @@ main(int argc, char **argv) if (fclose(fsuccess) || error) { - fflush(stdout); fprintf(stderr, "%s: write failed\n", touch); - exit(99); + exit(1); } } else { - fflush(stdout); fprintf(stderr, "%s: open failed\n", touch); - exit(99); + exit(1); } } return retval; } - -#else /* !PNG_SIMPLIFIED_READ_SUPPORTED */ -int main(void) -{ - fprintf(stderr, "pngstest: no read support in libpng, test skipped\n"); - /* So the test is skipped: */ - return 77; -} -#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ diff --git a/contrib/libtests/pngunknown.c b/contrib/libtests/pngunknown.c deleted file mode 100644 index 9d9acc0f7..000000000 --- a/contrib/libtests/pngunknown.c +++ /dev/null @@ -1,960 +0,0 @@ - -/* pngunknown.c - test the read side unknown chunk handling - * - * Last changed in libpng 1.6.0 [(PENDING RELEASE)] - * Copyright (c) 2013 Glenn Randers-Pehrson - * Written by John Cunningham Bowler - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * NOTES: - * This is a C program that is intended to be linked against libpng. It - * allows the libpng unknown handling code to be tested by interpreting - * arguments to save or discard combinations of chunks. The program is - * currently just a minimal validation for the built-in libpng facilities. - */ - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <setjmp.h> - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include <png.h> -#else -# include "../../png.h" -#endif - -#ifdef PNG_READ_SUPPORTED - -#if PNG_LIBPNG_VER < 10500 -/* This deliberately lacks the PNG_CONST. */ -typedef png_byte *png_const_bytep; - -/* This is copied from 1.5.1 png.h: */ -#define PNG_INTERLACE_ADAM7_PASSES 7 -#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7) -#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7) -#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) -#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) -#define PNG_PASS_ROWS(height, pass) (((height)+(((1<<PNG_PASS_ROW_SHIFT(pass))\ - -1)-PNG_PASS_START_ROW(pass)))>>PNG_PASS_ROW_SHIFT(pass)) -#define PNG_PASS_COLS(width, pass) (((width)+(((1<<PNG_PASS_COL_SHIFT(pass))\ - -1)-PNG_PASS_START_COL(pass)))>>PNG_PASS_COL_SHIFT(pass)) -#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ - (((yIn)<<PNG_PASS_ROW_SHIFT(pass))+PNG_PASS_START_ROW(pass)) -#define PNG_COL_FROM_PASS_COL(xIn, pass) \ - (((xIn)<<PNG_PASS_COL_SHIFT(pass))+PNG_PASS_START_COL(pass)) -#define PNG_PASS_MASK(pass,off) ( \ - ((0x110145AFU>>(((7-(off))-(pass))<<2)) & 0xFU) | \ - ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U)) -#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ - ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) -#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ - ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) - -/* These are needed too for the default build: */ -#define PNG_WRITE_16BIT_SUPPORTED -#define PNG_READ_16BIT_SUPPORTED - -/* This comes from pnglibconf.h afer 1.5: */ -#define PNG_FP_1 100000 -#define PNG_GAMMA_THRESHOLD_FIXED\ - ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) -#endif - -#if PNG_LIBPNG_VER < 10600 - /* 1.6.0 constifies many APIs. The following exists to allow pngvalid to be - * compiled against earlier versions. - */ -# define png_const_structp png_structp -#endif - - -/* Copied from pngpriv.h */ -#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) -#define PNG_CHUNK(b1,b2,b3,b4) \ - (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) - -#define png_IHDR PNG_CHUNK( 73, 72, 68, 82) -#define png_IDAT PNG_CHUNK( 73, 68, 65, 84) -#define png_IEND PNG_CHUNK( 73, 69, 78, 68) -#define png_PLTE PNG_CHUNK( 80, 76, 84, 69) -#define png_bKGD PNG_CHUNK( 98, 75, 71, 68) -#define png_cHRM PNG_CHUNK( 99, 72, 82, 77) -#define png_gAMA PNG_CHUNK(103, 65, 77, 65) -#define png_hIST PNG_CHUNK(104, 73, 83, 84) -#define png_iCCP PNG_CHUNK(105, 67, 67, 80) -#define png_iTXt PNG_CHUNK(105, 84, 88, 116) -#define png_oFFs PNG_CHUNK(111, 70, 70, 115) -#define png_pCAL PNG_CHUNK(112, 67, 65, 76) -#define png_sCAL PNG_CHUNK(115, 67, 65, 76) -#define png_pHYs PNG_CHUNK(112, 72, 89, 115) -#define png_sBIT PNG_CHUNK(115, 66, 73, 84) -#define png_sPLT PNG_CHUNK(115, 80, 76, 84) -#define png_sRGB PNG_CHUNK(115, 82, 71, 66) -#define png_sTER PNG_CHUNK(115, 84, 69, 82) -#define png_tEXt PNG_CHUNK(116, 69, 88, 116) -#define png_tIME PNG_CHUNK(116, 73, 77, 69) -#define png_tRNS PNG_CHUNK(116, 82, 78, 83) -#define png_zTXt PNG_CHUNK(122, 84, 88, 116) -#define png_vpAg PNG_CHUNK('v', 'p', 'A', 'g') - -/* Test on flag values as defined in the spec (section 5.4): */ -#define PNG_CHUNK_ANCILLARY(c ) (1 & ((c) >> 29)) -#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) -#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) -#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) -#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) - -/* Chunk information */ -#define PNG_INFO_tEXt 0x10000000U -#define PNG_INFO_iTXt 0x20000000U -#define PNG_INFO_zTXt 0x40000000U - -#define PNG_INFO_sTER 0x01000000U -#define PNG_INFO_vpAg 0x02000000U - -#define ABSENT 0 -#define START 1 -#define END 2 - -static struct -{ - char name[5]; - png_uint_32 flag; - png_uint_32 tag; - int unknown; /* Chunk not known to libpng */ - int all; /* Chunk set by the '-1' option */ - int position; /* position in pngtest.png */ - int keep; /* unknown handling setting */ -} chunk_info[] = { - /* Critical chunks */ - { "IDAT", PNG_INFO_IDAT, png_IDAT, 0, 0, START, 0 }, /* must be [0] */ - { "PLTE", PNG_INFO_PLTE, png_PLTE, 0, 0, ABSENT, 0 }, - - /* Non-critical chunks that libpng handles */ - { "bKGD", PNG_INFO_bKGD, png_bKGD, 0, 1, START, 0 }, - { "cHRM", PNG_INFO_cHRM, png_cHRM, 0, 1, START, 0 }, - { "gAMA", PNG_INFO_gAMA, png_gAMA, 0, 1, START, 0 }, - { "hIST", PNG_INFO_hIST, png_hIST, 0, 1, ABSENT, 0 }, - { "iCCP", PNG_INFO_iCCP, png_iCCP, 0, 1, ABSENT, 0 }, - { "iTXt", PNG_INFO_iTXt, png_iTXt, 0, 1, ABSENT, 0 }, - { "oFFs", PNG_INFO_oFFs, png_oFFs, 0, 1, START, 0 }, - { "pCAL", PNG_INFO_pCAL, png_pCAL, 0, 1, START, 0 }, - { "pHYs", PNG_INFO_pHYs, png_pHYs, 0, 1, START, 0 }, - { "sBIT", PNG_INFO_sBIT, png_sBIT, 0, 1, START, 0 }, - { "sCAL", PNG_INFO_sCAL, png_sCAL, 0, 1, START, 0 }, - { "sPLT", PNG_INFO_sPLT, png_sPLT, 0, 1, ABSENT, 0 }, - { "sRGB", PNG_INFO_sRGB, png_sRGB, 0, 1, START, 0 }, - { "tEXt", PNG_INFO_tEXt, png_tEXt, 0, 1, START, 0 }, - { "tIME", PNG_INFO_tIME, png_tIME, 0, 1, START, 0 }, - { "tRNS", PNG_INFO_tRNS, png_tRNS, 0, 0, ABSENT, 0 }, - { "zTXt", PNG_INFO_zTXt, png_zTXt, 0, 1, END, 0 }, - - /* No libpng handling */ - { "sTER", PNG_INFO_sTER, png_sTER, 1, 1, START, 0 }, - { "vpAg", PNG_INFO_vpAg, png_vpAg, 1, 0, START, 0 }, -}; - -#define NINFO ((int)((sizeof chunk_info)/(sizeof chunk_info[0]))) - -static void -clear_keep(void) -{ - int i = NINFO; - while (--i >= 0) - chunk_info[i].keep = 0; -} - -static int -find(const char *name) -{ - int i = NINFO; - while (--i >= 0) - { - if (memcmp(chunk_info[i].name, name, 4) == 0) - break; - } - - return i; -} - -static int -findb(const png_byte *name) -{ - int i = NINFO; - while (--i >= 0) - { - if (memcmp(chunk_info[i].name, name, 4) == 0) - break; - } - - return i; -} - -static int -find_by_flag(png_uint_32 flag) -{ - int i = NINFO; - - while (--i >= 0) if (chunk_info[i].flag == flag) return i; - - fprintf(stderr, "pngunknown: internal error\n"); - exit(4); -} - -static int -ancillary(const char *name) -{ - return PNG_CHUNK_ANCILLARY(PNG_CHUNK(name[0], name[1], name[2], name[3])); -} - -static int -ancillaryb(const png_byte *name) -{ - return PNG_CHUNK_ANCILLARY(PNG_CHUNK(name[0], name[1], name[2], name[3])); -} - -/* Type of an error_ptr */ -typedef struct -{ - jmp_buf error_return; - png_structp png_ptr; - png_infop info_ptr, end_ptr; - int error_count; - int warning_count; - const char *program; - const char *file; - const char *test; -} display; - -static const char init[] = "initialization"; -static const char cmd[] = "command line"; - -static void -init_display(display *d, const char *program) -{ - memset(d, 0, sizeof *d); - d->png_ptr = NULL; - d->info_ptr = d->end_ptr = NULL; - d->error_count = d->warning_count = 0; - d->program = program; - d->file = program; - d->test = init; -} - -static void -clean_display(display *d) -{ - png_destroy_read_struct(&d->png_ptr, &d->info_ptr, &d->end_ptr); - - /* This must not happen - it might cause an app crash */ - if (d->png_ptr != NULL || d->info_ptr != NULL || d->end_ptr != NULL) - { - fprintf(stderr, "%s(%s): png_destroy_read_struct error\n", d->file, - d->test); - exit(1); - } - - /* Invalidate the test */ - d->test = init; -} - -PNG_FUNCTION(void, display_exit, (display *d), static PNG_NORETURN) -{ - ++(d->error_count); - - if (d->png_ptr != NULL) - clean_display(d); - - /* During initialization and if this is a single command line argument set - * exit now - there is only one test, otherwise longjmp to do the next test. - */ - if (d->test == init || d->test == cmd) - exit(1); - - longjmp(d->error_return, 1); -} - -static int -display_rc(const display *d, int strict) -{ - return d->error_count + (strict ? d->warning_count : 0); -} - -/* libpng error and warning callbacks */ -PNG_FUNCTION(void, error, (png_structp png_ptr, const char *message), - static PNG_NORETURN) -{ - display *d = (display*)png_get_error_ptr(png_ptr); - - fprintf(stderr, "%s(%s): libpng error: %s\n", d->file, d->test, message); - display_exit(d); -} - -static void -warning(png_structp png_ptr, const char *message) -{ - display *d = (display*)png_get_error_ptr(png_ptr); - - fprintf(stderr, "%s(%s): libpng warning: %s\n", d->file, d->test, message); - ++(d->warning_count); -} - -static png_uint_32 -get_valid(display *d, png_infop info_ptr) -{ - png_uint_32 flags = png_get_valid(d->png_ptr, info_ptr, (png_uint_32)~0); - - /* Map the text chunks back into the flags */ - { - png_textp text; - png_uint_32 ntext = png_get_text(d->png_ptr, info_ptr, &text, NULL); - - while (ntext-- > 0) switch (text[ntext].compression) - { - case -1: - flags |= PNG_INFO_tEXt; - break; - case 0: - flags |= PNG_INFO_zTXt; - break; - case 1: - case 2: - flags |= PNG_INFO_iTXt; - break; - default: - fprintf(stderr, "%s(%s): unknown text compression %d\n", d->file, - d->test, text[ntext].compression); - display_exit(d); - } - } - - return flags; -} - -static png_uint_32 -get_unknown(display *d, int def, png_infop info_ptr) -{ - /* Create corresponding 'unknown' flags */ - png_uint_32 flags = 0; - { - png_unknown_chunkp unknown; - int num_unknown = png_get_unknown_chunks(d->png_ptr, info_ptr, &unknown); - - while (--num_unknown >= 0) - { - int chunk = findb(unknown[num_unknown].name); - - /* Chunks not known to pngunknown must be validated here; since they - * must also be unknown to libpng the 'def' behavior should have been - * used. - */ - if (chunk < 0) switch (def) - { - default: /* impossible */ - case PNG_HANDLE_CHUNK_AS_DEFAULT: - case PNG_HANDLE_CHUNK_NEVER: - fprintf(stderr, "%s(%s): %s: %s: unknown chunk saved\n", - d->file, d->test, def ? "discard" : "default", - unknown[num_unknown].name); - ++(d->error_count); - break; - - case PNG_HANDLE_CHUNK_IF_SAFE: - if (!ancillaryb(unknown[num_unknown].name)) - { - fprintf(stderr, - "%s(%s): if-safe: %s: unknown critical chunk saved\n", - d->file, d->test, unknown[num_unknown].name); - ++(d->error_count); - break; - } - /* FALL THROUGH (safe) */ - case PNG_HANDLE_CHUNK_ALWAYS: - break; - } - - else - flags |= chunk_info[chunk].flag; - } - } - - return flags; -} - -static int -check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, - display *d) -{ - int i, def = PNG_HANDLE_CHUNK_AS_DEFAULT, npasses, ipass; - png_uint_32 height; - - /* Some of these errors are permanently fatal and cause an exit here, others - * are per-test and cause an error return. - */ - d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, d, error, - warning); - if (d->png_ptr == NULL) - { - fprintf(stderr, "%s(%s): could not allocate png struct\n", d->file, - d->test); - /* Terminate here, this error is not test specific. */ - exit(1); - } - - d->info_ptr = png_create_info_struct(d->png_ptr); - d->end_ptr = png_create_info_struct(d->png_ptr); - if (d->info_ptr == NULL || d->end_ptr == NULL) - { - fprintf(stderr, "%s(%s): could not allocate png info\n", d->file, - d->test); - clean_display(d); - exit(1); - } - - png_init_io(d->png_ptr, fp); - - /* Handle each argument in turn; multiple settings are possible for the same - * chunk and multiple calls will occur (the last one should override all - * preceding ones). - */ - for (i=0; i<argc; ++i) - { - const char *equals = strchr(argv[i], '='); - - if (equals != NULL) - { - int chunk, option; - - if (strcmp(equals+1, "default") == 0) - option = PNG_HANDLE_CHUNK_AS_DEFAULT; - else if (strcmp(equals+1, "discard") == 0) - option = PNG_HANDLE_CHUNK_NEVER; - else if (strcmp(equals+1, "if-safe") == 0) - option = PNG_HANDLE_CHUNK_IF_SAFE; - else if (strcmp(equals+1, "save") == 0) - option = PNG_HANDLE_CHUNK_ALWAYS; - else - { - fprintf(stderr, "%s(%s): %s: unrecognized chunk option\n", d->file, - d->test, argv[i]); - display_exit(d); - } - - switch (equals - argv[i]) - { - case 4: /* chunk name */ - chunk = find(argv[i]); - - if (chunk >= 0) - { - /* These #if tests have the effect of skipping the arguments - * if SAVE support is unavailable - we can't do a useful test - * in this case, so we just check the arguments! This could - * be improved in the future by using the read callback. - */ -# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - png_byte name[5]; - - memcpy(name, chunk_info[chunk].name, 5); - png_set_keep_unknown_chunks(d->png_ptr, option, name, 1); - chunk_info[chunk].keep = option; -# endif - continue; - } - - break; - - case 7: /* default */ - if (memcmp(argv[i], "default", 7) == 0) - { -# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0); -# endif - def = option; - continue; - } - - break; - - case 3: /* all */ - if (memcmp(argv[i], "all", 3) == 0) - { -# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1); - def = option; - - for (chunk = 0; chunk < NINFO; ++chunk) - if (chunk_info[chunk].all) - chunk_info[chunk].keep = option; -# endif - continue; - } - - break; - - default: /* some misplaced = */ - - break; - } - } - - fprintf(stderr, "%s(%s): %s: unrecognized chunk argument\n", d->file, - d->test, argv[i]); - display_exit(d); - } - - png_read_info(d->png_ptr, d->info_ptr); - - switch (png_get_interlace_type(d->png_ptr, d->info_ptr)) - { - case PNG_INTERLACE_NONE: - npasses = 1; - break; - - case PNG_INTERLACE_ADAM7: - npasses = PNG_INTERLACE_ADAM7_PASSES; - break; - - default: - /* Hard error because it is not test specific */ - fprintf(stderr, "%s(%s): invalid interlace type\n", d->file, d->test); - clean_display(d); - exit(1); - } - - /* Skip the image data, if IDAT is not being handled then don't do this - * because it will cause a CRC error. - */ - if (chunk_info[0/*IDAT*/].keep == PNG_HANDLE_CHUNK_AS_DEFAULT) - { - png_start_read_image(d->png_ptr); - height = png_get_image_height(d->png_ptr, d->info_ptr); - - if (npasses > 1) - { - png_uint_32 width = png_get_image_width(d->png_ptr, d->info_ptr); - - for (ipass=0; ipass<npasses; ++ipass) - { - png_uint_32 wPass = PNG_PASS_COLS(width, ipass); - - if (wPass > 0) - { - png_uint_32 y; - - for (y=0; y<height; ++y) if (PNG_ROW_IN_INTERLACE_PASS(y, ipass)) - png_read_row(d->png_ptr, NULL, NULL); - } - } - } /* interlaced */ - - else /* not interlaced */ - { - png_uint_32 y; - - for (y=0; y<height; ++y) - png_read_row(d->png_ptr, NULL, NULL); - } - } - - png_read_end(d->png_ptr, d->end_ptr); - - flags[0] = get_valid(d, d->info_ptr); - flags[1] = get_unknown(d, def, d->info_ptr); - - /* Only png_read_png sets PNG_INFO_IDAT! */ - flags[chunk_info[0/*IDAT*/].keep != PNG_HANDLE_CHUNK_AS_DEFAULT] |= - PNG_INFO_IDAT; - - flags[2] = get_valid(d, d->end_ptr); - flags[3] = get_unknown(d, def, d->end_ptr); - - clean_display(d); - - return def; -} - -static void -check_error(display *d, png_uint_32 flags, const char *message) -{ - while (flags) - { - png_uint_32 flag = flags & -(png_int_32)flags; - int i = find_by_flag(flag); - - fprintf(stderr, "%s(%s): chunk %s: %s\n", d->file, d->test, - chunk_info[i].name, message); - ++(d->error_count); - - flags &= ~flag; - } -} - -static void -check_handling(display *d, int def, png_uint_32 chunks, png_uint_32 known, - png_uint_32 unknown, const char *position) -{ - while (chunks) - { - png_uint_32 flag = chunks & -(png_int_32)chunks; - int i = find_by_flag(flag); - int keep = chunk_info[i].keep; - const char *type; - const char *errorx = NULL; - - if (chunk_info[i].unknown) - { - if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) - { - type = "UNKNOWN (default)"; - keep = def; - } - - else - type = "UNKNOWN (specified)"; - - if (flag & known) - errorx = "chunk processed"; - - else switch (keep) - { - case PNG_HANDLE_CHUNK_AS_DEFAULT: - if (flag & unknown) - errorx = "DEFAULT: unknown chunk saved"; - break; - - case PNG_HANDLE_CHUNK_NEVER: - if (flag & unknown) - errorx = "DISCARD: unknown chunk saved"; - break; - - case PNG_HANDLE_CHUNK_IF_SAFE: - if (ancillary(chunk_info[i].name)) - { - if (!(flag & unknown)) - errorx = "IF-SAFE: unknown ancillary chunk lost"; - } - - else if (flag & unknown) - errorx = "IF-SAFE: unknown critical chunk saved"; - break; - - case PNG_HANDLE_CHUNK_ALWAYS: - if (!(flag & unknown)) - errorx = "SAVE: unknown chunk lost"; - break; - - default: - errorx = "internal error: bad keep"; - break; - } - } /* unknown chunk */ - - else /* known chunk */ - { - type = "KNOWN"; - - if (flag & known) - { - /* chunk was processed, it won't have been saved because that is - * caught below when checking for inconsistent processing. - */ - if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT) - errorx = "!DEFAULT: known chunk processed"; - } - - else /* not processed */ switch (keep) - { - case PNG_HANDLE_CHUNK_AS_DEFAULT: - errorx = "DEFAULT: known chunk not processed"; - break; - - case PNG_HANDLE_CHUNK_NEVER: - if (flag & unknown) - errorx = "DISCARD: known chunk saved"; - break; - - case PNG_HANDLE_CHUNK_IF_SAFE: - if (ancillary(chunk_info[i].name)) - { - if (!(flag & unknown)) - errorx = "IF-SAFE: known ancillary chunk lost"; - } - - else if (flag & unknown) - errorx = "IF-SAFE: known critical chunk saved"; - break; - - case PNG_HANDLE_CHUNK_ALWAYS: - if (!(flag & unknown)) - errorx = "SAVE: known chunk lost"; - break; - - default: - errorx = "internal error: bad keep (2)"; - break; - } - } - - if (errorx != NULL) - { - ++(d->error_count); - fprintf(stderr, "%s(%s): %s %s %s: %s\n", - d->file, d->test, type, chunk_info[i].name, position, errorx); - } - - chunks &= ~flag; - } -} - -static void -perform_one_test(FILE *fp, int argc, const char **argv, - png_uint_32 *default_flags, display *d) -{ - int def; - png_uint_32 flags[2][4]; - - rewind(fp); - clear_keep(); - memcpy(flags[0], default_flags, sizeof flags[0]); - - def = check(fp, argc, argv, flags[1], d); - - /* Chunks should either be known or unknown, never both and this should apply - * whether the chunk is before or after the IDAT (actually, the app can - * probably change this by swapping the handling after the image, but this - * test does not do that.) - */ - check_error(d, (flags[0][0]|flags[0][2]) & (flags[0][1]|flags[0][3]), - "chunk handled inconsistently in count tests"); - check_error(d, (flags[1][0]|flags[1][2]) & (flags[1][1]|flags[1][3]), - "chunk handled inconsistently in option tests"); - - /* Now find out what happened to each chunk before and after the IDAT and - * determine if the behavior was correct. First some basic sanity checks, - * any known chunk should be known in the original count, any unknown chunk - * should be either known or unknown in the original. - */ - { - png_uint_32 test; - - test = flags[1][0] & ~flags[0][0]; - check_error(d, test, "new known chunk before IDAT"); - test = flags[1][1] & ~(flags[0][0] | flags[0][1]); - check_error(d, test, "new unknown chunk before IDAT"); - test = flags[1][2] & ~flags[0][2]; - check_error(d, test, "new known chunk after IDAT"); - test = flags[1][3] & ~(flags[0][2] | flags[0][3]); - check_error(d, test, "new unknown chunk after IDAT"); - } - - /* Now each chunk in the original list should have been handled according to - * the options set for that chunk, regardless of whether libpng knows about - * it or not. - */ - check_handling(d, def, flags[0][0] | flags[0][1], flags[1][0], flags[1][1], - "before IDAT"); - check_handling(d, def, flags[0][2] | flags[0][3], flags[1][2], flags[1][3], - "after IDAT"); -} - -static void -perform_one_test_safe(FILE *fp, int argc, const char **argv, - png_uint_32 *default_flags, display *d, const char *test) -{ - if (setjmp(d->error_return) == 0) - { - d->test = test; /* allow use of d->error_return */ - perform_one_test(fp, argc, argv, default_flags, d); - d->test = init; /* prevent use of d->error_return */ - } -} - -static const char *standard_tests[] = -{ - "discard", "default=discard", 0, - "save", "default=save", 0, - "if-safe", "default=if-safe", 0, - "vpAg", "vpAg=if-safe", 0, - "sTER", "sTER=if-safe", 0, - "IDAT", "default=discard", "IDAT=save", 0, - "sAPI", "bKGD=save", "cHRM=save", "gAMA=save", "all=discard", "iCCP=save", - "sBIT=save", "sRGB=save", 0, - 0/*end*/ -}; - -static PNG_NORETURN void -usage(const char *program, const char *reason) -{ - fprintf(stderr, "pngunknown: %s: usage:\n %s [--strict] " - "--default|{(CHNK|default|all)=(default|discard|if-safe|save)} " - "testfile.png\n", reason, program); - exit(2); -} - -int -main(int argc, const char **argv) -{ - FILE *fp; - png_uint_32 default_flags[4/*valid,unknown{before,after}*/]; - int strict = 0, default_tests = 0; - const char *count_argv = "default=save"; - const char *touch_file = NULL; - display d; - - init_display(&d, argv[0]); - - while (++argv, --argc > 0) - { - if (strcmp(*argv, "--strict") == 0) - strict = 1; - - else if (strcmp(*argv, "--default") == 0) - default_tests = 1; - - else if (strcmp(*argv, "--touch") == 0) - { - if (argc > 1) - touch_file = *++argv, --argc; - - else - usage(d.program, "--touch: missing file name"); - } - - else - break; - } - - /* A file name is required, but there should be no other arguments if - * --default was specified. - */ - if (argc <= 0) - usage(d.program, "missing test file"); - - /* GCC BUG: if (default_tests && argc != 1) triggers some weird GCC argc - * optimization which causes warnings with -Wstrict-overflow! - */ - else if (default_tests) if (argc != 1) - usage(d.program, "extra arguments"); - -# ifndef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - fprintf(stderr, "%s: warning: no 'save' support so arguments ignored\n", - d.program); -# endif - - /* The name of the test file is the last argument; remove it. */ - d.file = argv[--argc]; - - fp = fopen(d.file, "rb"); - if (fp == NULL) - { - perror(d.file); - exit(2); - } - - /* First find all the chunks, known and unknown, in the test file, a failure - * here aborts the whole test. - */ - if (check(fp, 1, &count_argv, default_flags, &d) != - PNG_HANDLE_CHUNK_ALWAYS) - { - fprintf(stderr, "%s: %s: internal error\n", d.program, d.file); - exit(3); - } - - /* Now find what the various supplied options cause to change: */ - if (!default_tests) - { - d.test = cmd; /* acts as a flag to say exit, do not longjmp */ - perform_one_test(fp, argc, argv, default_flags, &d); - d.test = init; - } - - else - { - const char **test = standard_tests; - - /* Set the exit_test pointer here so we can continue after a libpng error. - * NOTE: this leaks memory because the png_struct data from the failing - * test is never freed. - */ - while (*test) - { - const char *this_test = *test++; - const char **next = test; - int count = display_rc(&d, strict), new_count; - const char *result; - int arg_count = 0; - - while (*next) ++next, ++arg_count; - - perform_one_test_safe(fp, arg_count, test, default_flags, &d, - this_test); - - new_count = display_rc(&d, strict); - - if (new_count == count) - result = "PASS"; - - else - result = "FAIL"; - - printf("%s: %s %s\n", result, d.program, this_test); - - test = next+1; - } - } - - fclose(fp); - - if (display_rc(&d, strict) == 0) - { - /* Success, touch the success file if appropriate */ - if (touch_file != NULL) - { - FILE *fsuccess = fopen(touch_file, "wt"); - - if (fsuccess != NULL) - { - int err = 0; - fprintf(fsuccess, "PNG unknown tests succeeded\n"); - fflush(fsuccess); - err = ferror(fsuccess); - - if (fclose(fsuccess) || err) - { - fprintf(stderr, "%s: write failed\n", touch_file); - exit(1); - } - } - - else - { - fprintf(stderr, "%s: open failed\n", touch_file); - exit(1); - } - } - - return 0; - } - - return 1; -} - -#else -int -main(void) -{ - fprintf(stderr, - " test ignored because libpng was not built with unknown chunk support\n"); - return 0; -} -#endif diff --git a/contrib/libtests/pngvalid.c b/contrib/libtests/pngvalid.c index cc4e8aa9f..52f893a94 100644 --- a/contrib/libtests/pngvalid.c +++ b/contrib/libtests/pngvalid.c @@ -1,8 +1,8 @@ /* pngvalid.c - validate libpng by constructing then reading png files. * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 2013 Glenn Randers-Pehrson + * Last changed in libpng 1.6.0 [(PENDING RELEASE)] + * Copyright (c) 2012 Glenn Randers-Pehrson * Written by John Cunningham Bowler * * This code is released under the libpng license. @@ -24,9 +24,8 @@ #define _GNU_SOURCE 1 /* For the floating point exception extension */ #include <signal.h> -#include <stdio.h> -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +#if (defined HAVE_CONFIG_H) && !(defined PNG_NO_CONFIG_H) # include <config.h> #endif @@ -43,8 +42,6 @@ # include "../../png.h" #endif -#ifdef PNG_WRITE_SUPPORTED /* else pngvalid can do nothing */ - #if PNG_LIBPNG_VER < 10500 /* This deliberately lacks the PNG_CONST. */ typedef png_byte *png_const_bytep; @@ -85,10 +82,10 @@ typedef png_byte *png_const_bytep; /* 1.6.0 constifies many APIs, the following exists to allow pngvalid to be * compiled against earlier versions. */ -# define png_const_structp png_structp +# define png_const_strutp png_structp #endif -#include <zlib.h> /* For crc32 */ +#include "zlib.h" /* For crc32 */ #include <float.h> /* For floating point constants */ #include <stdlib.h> /* For malloc */ @@ -107,11 +104,7 @@ typedef png_byte *png_const_bytep; #endif /***************************** EXCEPTION HANDLING *****************************/ -#ifdef PNG_FREESTANDING_TESTS -# include <cexcept.h> -#else -# include "../visupng/cexcept.h" -#endif +#include "../visupng/cexcept.h" #ifdef __cplusplus # define this not_the_cpp_this @@ -177,7 +170,6 @@ static PNG_CONST char *colour_types[8] = "grayscale with alpha", invalid, "truecolour with alpha", invalid }; -#ifdef PNG_READ_SUPPORTED /* Convert a double precision value to fixed point. */ static png_fixed_point fix(double d) @@ -185,14 +177,12 @@ fix(double d) d = floor(d * PNG_FP_1 + .5); return (png_fixed_point)d; } -#endif /* PNG_READ_SUPPORTED */ /* Generate random bytes. This uses a boring repeatable algorithm and it * is implemented here so that it gives the same set of numbers on every * architecture. It's a linear congruential generator (Knuth or Sedgewick * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and - * Hill, "The Art of Electronics" (Pseudo-Random Bit Sequences and Noise - * Generation.) + * Hill, "The Art of Electronics". */ static void make_random_bytes(png_uint_32* seed, void* pv, size_t size) @@ -225,7 +215,6 @@ make_four_random_bytes(png_uint_32* seed, png_bytep bytes) make_random_bytes(seed, bytes, 4); } -#ifdef PNG_READ_SUPPORTED static void randomize(void *pv, size_t size) { @@ -245,7 +234,6 @@ random_mod(unsigned int max) return x % max; /* 0 .. max-1 */ } -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED static int random_choice(void) { @@ -255,8 +243,6 @@ random_choice(void) return x & 1; } -#endif -#endif /* PNG_READ_SUPPORTED */ /* A numeric ID based on PNG file characteristics. The 'do_interlace' field * simply records whether pngvalid did the interlace itself or whether it @@ -269,7 +255,7 @@ random_choice(void) #define COL_FROM_ID(id) ((png_byte)((id)& 0x7U)) #define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU)) -#define PALETTE_FROM_ID(id) (((id) >> 8) & 0x1f) +#define PALETTE_FROM_ID(id) ((int)(((id) >> 8) & 0x1f)) #define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3)) #define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1)) #define WIDTH_FROM_ID(id) (((id)>>16) & 0xff) @@ -278,7 +264,7 @@ random_choice(void) /* Utility to construct a standard name for a standard image. */ static size_t standard_name(char *buffer, size_t bufsize, size_t pos, png_byte colour_type, - int bit_depth, unsigned int npalette, int interlace_type, + int bit_depth, int npalette, int interlace_type, png_uint_32 w, png_uint_32 h, int do_interlace) { pos = safecat(buffer, bufsize, pos, colour_types[colour_type]); @@ -340,11 +326,10 @@ standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id) /* The following defines the number of different palettes to generate for * each log bit depth of a colour type 3 standard image. */ -#define PALETTE_COUNT(bit_depth) ((bit_depth) > 4 ? 1U : 16U) +#define PALETTE_COUNT(bit_depth) ((bit_depth) > 4 ? 1 : 16) static int -next_format(png_bytep colour_type, png_bytep bit_depth, - unsigned int* palette_number) +next_format(png_bytep colour_type, png_bytep bit_depth, int* palette_number) { if (*bit_depth == 0) { @@ -475,7 +460,6 @@ pixel_copy(png_bytep toBuffer, png_uint_32 toIndex, memmove(toBuffer+(toIndex>>3), fromBuffer+(fromIndex>>3), pixelSize>>3); } -#ifdef PNG_READ_SUPPORTED /* Copy a complete row of pixels, taking into account potential partial * bytes at the end. */ @@ -541,7 +525,6 @@ pixel_cmp(png_const_bytep pa, png_const_bytep pb, png_uint_32 bit_width) return 1+where; } } -#endif /* PNG_READ_SUPPORTED */ /*************************** BASIC PNG FILE WRITING ***************************/ /* A png_store takes data from the sequential writer or provides data @@ -652,7 +635,6 @@ store_pool_mark(png_bytep mark) make_four_random_bytes(store_seed, mark); } -#ifdef PNG_READ_SUPPORTED /* Use this for random 32 bit values; this function makes sure the result is * non-zero. */ @@ -672,7 +654,6 @@ random_32(void) return result; } } -#endif /* PNG_READ_SUPPORTED */ static void store_pool_init(png_store *ps, store_pool *pool) @@ -878,7 +859,6 @@ store_log(png_store* ps, png_const_structp pp, png_const_charp message, store_verbose(ps, pp, is_error ? "error: " : "warning: ", message); } -#ifdef PNG_READ_SUPPORTED /* Internal error function, called with a png_store but no libpng stuff. */ static void internal_error(png_store *ps, png_const_charp message) @@ -891,7 +871,6 @@ internal_error(png_store *ps, png_const_charp message) Throw ps; } } -#endif /* PNG_READ_SUPPORTED */ /* Functions to use as PNG callbacks. */ static void @@ -1029,7 +1008,6 @@ store_ensure_image(png_store *ps, png_const_structp pp, int nImages, } } -#ifdef PNG_READ_SUPPORTED static void store_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage) { @@ -1059,7 +1037,6 @@ store_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage) } } } -#endif /* PNG_READ_SUPPORTED */ static void store_write(png_structp ppIn, png_bytep pb, png_size_t st) @@ -1095,7 +1072,6 @@ store_flush(png_structp ppIn) UNUSED(ppIn) /*DOES NOTHING*/ } -#ifdef PNG_READ_SUPPORTED static size_t store_read_buffer_size(png_store *ps) { @@ -1213,7 +1189,6 @@ store_progressive_read(png_store *ps, png_structp pp, png_infop pi) } while (store_read_buffer_next(ps)); } -#endif /* PNG_READ_SUPPORTED */ /* The caller must fill this in: */ static store_palette_entry * @@ -1240,7 +1215,6 @@ store_write_palette(png_store *ps, int npalette) return ps->palette; } -#ifdef PNG_READ_SUPPORTED static store_palette_entry * store_current_palette(png_store *ps, int *npalette) { @@ -1254,7 +1228,6 @@ store_current_palette(png_store *ps, int *npalette) *npalette = ps->current->npalette; return ps->current->palette; } -#endif /* PNG_READ_SUPPORTED */ /***************************** MEMORY MANAGEMENT*** ***************************/ /* A store_memory is simply the header for an allocated block of memory. The @@ -1529,29 +1502,25 @@ set_store_for_write(png_store *ps, png_infopp ppi, } /* Cleanup when finished reading (either due to error or in the success case). - * This routine exists even when there is no read support to make the code - * tidier (avoid a mass of ifdefs) and so easier to maintain. */ static void store_read_reset(png_store *ps) { -# ifdef PNG_READ_SUPPORTED - if (ps->pread != NULL) - { - anon_context(ps); - - Try - png_destroy_read_struct(&ps->pread, &ps->piread, NULL); + if (ps->pread != NULL) + { + anon_context(ps); - Catch_anonymous - { - /* error already output: continue */ - } + Try + png_destroy_read_struct(&ps->pread, &ps->piread, NULL); - ps->pread = NULL; - ps->piread = NULL; + Catch_anonymous + { + /* error already output: continue */ } -# endif + + ps->pread = NULL; + ps->piread = NULL; + } /* Always do this to be safe. */ store_pool_delete(ps, &ps->read_memory_pool); @@ -1562,7 +1531,6 @@ store_read_reset(png_store *ps) ps->validated = 0; } -#ifdef PNG_READ_SUPPORTED static void store_read_set(png_store *ps, png_uint_32 id) { @@ -1640,7 +1608,6 @@ set_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id, return ps->pread; } -#endif /* PNG_READ_SUPPORTED */ /* The overall cleanup of a store simply calls the above then removes all the * saved files. This does not delete the store itself. @@ -1680,19 +1647,6 @@ typedef struct CIE_color double X, Y, Z; } CIE_color; -typedef struct color_encoding -{ - /* A description of an (R,G,B) encoding of color (as defined above); this - * includes the actual colors of the (R,G,B) triples (1,0,0), (0,1,0) and - * (0,0,1) plus an encoding value that is used to encode the linear - * components R, G and B to give the actual values R^gamma, G^gamma and - * B^gamma that are stored. - */ - double gamma; /* Encoding (file) gamma of space */ - CIE_color red, green, blue; /* End points */ -} color_encoding; - -#ifdef PNG_READ_SUPPORTED static double chromaticity_x(CIE_color c) { @@ -1705,11 +1659,23 @@ 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; @@ -1717,7 +1683,6 @@ white_point(PNG_CONST color_encoding *encoding) return white; } -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED static void normalize_color_encoding(color_encoding *encoding) { @@ -1737,7 +1702,6 @@ normalize_color_encoding(color_encoding *encoding) encoding->blue.Z /= whiteY; } } -#endif static size_t safecat_color_encoding(char *buffer, size_t bufsize, size_t pos, @@ -1778,7 +1742,6 @@ safecat_color_encoding(char *buffer, size_t bufsize, size_t pos, return pos; } -#endif /* PNG_READ_SUPPORTED */ typedef struct png_modifier { @@ -1972,7 +1935,6 @@ modifier_init(png_modifier *pm) * to a calculation - not a digitization operation - unless the following API is * called directly. */ -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED static double digitize(PNG_CONST png_modifier *pm, double value, int sample_depth, int do_round) { @@ -1997,10 +1959,7 @@ static double digitize(PNG_CONST png_modifier *pm, double value, if (do_round) value += .5; return floor(value)/digitization_factor; } -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) { /* Absolute error permitted in linear values - affected by the bit depth of @@ -2012,9 +1971,7 @@ static double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) else return pm->maxabs8; } -#endif -#ifdef PNG_READ_GAMMA_SUPPORTED static double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) { /* Error in the linear composition arithmetic - only relevant when @@ -2131,7 +2088,6 @@ static int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth, else return 1; } -#endif /* PNG_READ_GAMMA_SUPPORTED */ /* One modification structure must be provided for each chunk to be modified (in * fact more than one can be provided if multiple separate changes are desired @@ -2184,7 +2140,6 @@ modification_init(png_modification *pmm) modification_reset(pmm); } -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED static void modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce) { @@ -2196,7 +2151,6 @@ modifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce) ce->gamma = pm->current_gamma; } -#endif static size_t safecat_current_encoding(char *buffer, size_t bufsize, size_t pos, @@ -2822,7 +2776,6 @@ srgb_modification_init(srgb_modification *me, png_modifier *pm, png_byte intent) pm->modifications = &me->this; } -#ifdef PNG_READ_GAMMA_SUPPORTED typedef struct sbit_modification { png_modification this; @@ -2889,7 +2842,6 @@ sbit_modification_init(sbit_modification *me, png_modifier *pm, png_byte sbit) me->this.next = pm->modifications; pm->modifications = &me->this; } -#endif /* PNG_READ_GAMMA_SUPPORTED */ #endif /* PNG_READ_TRANSFORMS_SUPPORTED */ /***************************** STANDARD PNG FILES *****************************/ @@ -2951,9 +2903,9 @@ make_standard_palette(png_store* ps, int npalette, int do_tRNS) */ for (; i<8; ++i) { - values[i][1] = (png_byte)((i&1) ? 255U : 0U); - values[i][2] = (png_byte)((i&2) ? 255U : 0U); - values[i][3] = (png_byte)((i&4) ? 255U : 0U); + values[i][1] = (i&1) ? 255 : 0; + values[i][2] = (i&2) ? 255 : 0; + values[i][3] = (i&4) ? 255 : 0; } /* Then add 62 grays (one quarter of the remaining 256 slots). */ @@ -3168,7 +3120,6 @@ transform_height(png_const_structp pp, png_byte colour_type, png_byte bit_depth) } } -#ifdef PNG_READ_SUPPORTED /* The following can only be defined here, now we have the definitions * of the transform image sizes. */ @@ -3204,7 +3155,6 @@ standard_rowsize(png_const_structp pp, png_uint_32 id) width *= bit_size(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); return (width + 7) / 8; } -#endif /* PNG_READ_SUPPORTED */ static void transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], @@ -3216,20 +3166,20 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], switch (bit_size(pp, colour_type, bit_depth)) { case 1: - while (i<128/8) buffer[i] = (png_byte)(v & 0xff), v += 17, ++i; + while (i<128/8) buffer[i] = v & 0xff, v += 17, ++i; return; case 2: - while (i<128/4) buffer[i] = (png_byte)(v & 0xff), v += 33, ++i; + while (i<128/4) buffer[i] = v & 0xff, v += 33, ++i; return; case 4: - while (i<128/2) buffer[i] = (png_byte)(v & 0xff), v += 65, ++i; + while (i<128/2) buffer[i] = v & 0xff, v += 65, ++i; return; case 8: /* 256 bytes total, 128 bytes in each row set as follows: */ - while (i<128) buffer[i] = (png_byte)(v & 0xff), ++v, ++i; + while (i<128) buffer[i] = v & 0xff, ++v, ++i; return; case 16: @@ -3237,12 +3187,7 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], * GA case as well as the 16 bit G case. */ while (i<128) - { - buffer[2*i] = (png_byte)((v>>8) & 0xff); - buffer[2*i+1] = (png_byte)(v & 0xff); - ++v; - ++i; - } + buffer[2*i] = (v>>8) & 0xff, buffer[2*i+1] = v & 0xff, ++v, ++i; return; @@ -3251,9 +3196,9 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], while (i<128) { /* Three bytes per pixel, r, g, b, make b by r^g */ - buffer[3*i+0] = (png_byte)((v >> 8) & 0xff); - buffer[3*i+1] = (png_byte)(v & 0xff); - buffer[3*i+2] = (png_byte)(((v >> 8) ^ v) & 0xff); + buffer[3*i+0] = (v >> 8) & 0xff; + buffer[3*i+1] = v & 0xff; + buffer[3*i+2] = ((v >> 8) ^ v) & 0xff; ++v; ++i; } @@ -3264,10 +3209,10 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], /* 65535 pixels, r, g, b, a; just replicate */ while (i<128) { - buffer[4*i+0] = (png_byte)((v >> 8) & 0xff); - buffer[4*i+1] = (png_byte)(v & 0xff); - buffer[4*i+2] = (png_byte)((v >> 8) & 0xff); - buffer[4*i+3] = (png_byte)(v & 0xff); + buffer[4*i+0] = (v >> 8) & 0xff; + buffer[4*i+1] = v & 0xff; + buffer[4*i+2] = (v >> 8) & 0xff; + buffer[4*i+3] = v & 0xff; ++v; ++i; } @@ -3281,14 +3226,14 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], while (i<128) { png_uint_32 t = v++; - buffer[6*i+0] = (png_byte)((t >> 8) & 0xff); - buffer[6*i+1] = (png_byte)(t & 0xff); + buffer[6*i+0] = (t >> 8) & 0xff; + buffer[6*i+1] = t & 0xff; t *= 257; - buffer[6*i+2] = (png_byte)((t >> 8) & 0xff); - buffer[6*i+3] = (png_byte)(t & 0xff); + buffer[6*i+2] = (t >> 8) & 0xff; + buffer[6*i+3] = t & 0xff; t *= 17; - buffer[6*i+4] = (png_byte)((t >> 8) & 0xff); - buffer[6*i+5] = (png_byte)(t & 0xff); + buffer[6*i+4] = (t >> 8) & 0xff; + buffer[6*i+5] = t & 0xff; ++i; } @@ -3299,15 +3244,15 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], while (i<128) { png_uint_32 t = v++; - buffer[8*i+0] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+1] = (png_byte)(t & 0xff); - buffer[8*i+4] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+5] = (png_byte)(t & 0xff); + buffer[8*i+0] = (t >> 8) & 0xff; + buffer[8*i+1] = t & 0xff; + buffer[8*i+4] = (t >> 8) & 0xff; + buffer[8*i+5] = t & 0xff; t *= 257; - buffer[8*i+2] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+3] = (png_byte)(t & 0xff); - buffer[8*i+6] = (png_byte)((t >> 8) & 0xff); - buffer[8*i+7] = (png_byte)(t & 0xff); + buffer[8*i+2] = (t >> 8) & 0xff; + buffer[8*i+3] = t & 0xff; + buffer[8*i+6] = (t >> 8) & 0xff; + buffer[8*i+7] = t & 0xff; ++i; } return; @@ -3332,8 +3277,8 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], */ static void make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, - png_byte PNG_CONST bit_depth, unsigned int palette_number, - int interlace_type, png_const_charp name) + png_byte PNG_CONST bit_depth, int palette_number, int interlace_type, + png_const_charp name) { context(ps, fault); @@ -3357,11 +3302,6 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #ifdef PNG_TEXT_SUPPORTED -# if defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED) -# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_zTXt -# else -# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_NONE -# endif { static char key[] = "image name"; /* must be writeable */ size_t pos; @@ -3371,7 +3311,7 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, /* Use a compressed text string to test the correct interaction of text * compression and IDAT compression. */ - text.compression = TEXT_COMPRESSION; + text.compression = PNG_TEXT_COMPRESSION_zTXt; text.key = key; /* Yuck: the text must be writable! */ pos = safecat(copy, sizeof copy, 0, ps->wname); @@ -3429,7 +3369,7 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, /* Use a compressed text string to test the correct interaction of text * compression and IDAT compression. */ - text.compression = TEXT_COMPRESSION; + text.compression = PNG_TEXT_COMPRESSION_zTXt; text.key = key; text.text = comment; text.text_length = (sizeof comment)-1; @@ -3465,7 +3405,7 @@ make_transform_images(png_store *ps) { png_byte colour_type = 0; png_byte bit_depth = 0; - unsigned int palette_number = 0; + int palette_number = 0; /* This is in case of errors. */ safecat(ps->test, sizeof ps->test, 0, "make standard images"); @@ -3513,7 +3453,6 @@ interlace_row(png_bytep buffer, png_const_bytep imageRow, } } -#ifdef PNG_READ_SUPPORTED static void deinterlace_row(png_bytep buffer, png_const_bytep row, unsigned int pixel_size, png_uint_32 w, int pass) @@ -3534,7 +3473,6 @@ deinterlace_row(png_bytep buffer, png_const_bytep row, ++xin; } } -#endif /* PNG_READ_SUPPORTED */ /* Build a single row for the 'size' test images; this fills in only the * first bit_width bits of the sample row. @@ -3592,30 +3530,6 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); -#ifdef PNG_TEXT_SUPPORTED - { - static char key[] = "image name"; /* must be writeable */ - size_t pos; - png_text text; - char copy[FILE_NAME_SIZE]; - - /* Use a compressed text string to test the correct interaction of text - * compression and IDAT compression. - */ - text.compression = TEXT_COMPRESSION; - text.key = key; - /* Yuck: the text must be writable! */ - pos = safecat(copy, sizeof copy, 0, ps->wname); - text.text = copy; - text.text_length = pos; - text.itxt_length = 0; - text.lang = 0; - text.lang_key = 0; - - png_set_text(pp, pi, &text, 1); - } -#endif - if (colour_type == 3) /* palette */ init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/); @@ -3693,27 +3607,6 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, } } -#ifdef PNG_TEXT_SUPPORTED - { - static char key[] = "end marker"; - static char comment[] = "end"; - png_text text; - - /* Use a compressed text string to test the correct interaction of text - * compression and IDAT compression. - */ - text.compression = TEXT_COMPRESSION; - text.key = key; - text.text = comment; - text.text_length = (sizeof comment)-1; - text.itxt_length = 0; - text.lang = 0; - text.lang_key = 0; - - png_set_text(pp, pi, &text, 1); - } -#endif - png_write_end(pp, pi); /* And store this under the appropriate id, then clean up. */ @@ -3778,7 +3671,6 @@ make_size_images(png_store *ps) make_size(ps, 6, 3, WRITE_BDHI); } -#ifdef PNG_READ_SUPPORTED /* Return a row based on image id and 'y' for checking: */ static void standard_row(png_const_structp pp, png_byte std[STANDARD_ROWMAX], @@ -3790,7 +3682,6 @@ standard_row(png_const_structp pp, png_byte std[STANDARD_ROWMAX], size_row(std, WIDTH_FROM_ID(id) * bit_size(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)), y); } -#endif /* PNG_READ_SUPPORTED */ /* Tests - individual test cases */ /* Like 'make_standard' but errors are deliberately introduced into the calls @@ -4075,7 +3966,6 @@ perform_formatting_test(png_store *volatile ps) #endif } -#ifdef PNG_READ_SUPPORTED /* Because we want to use the same code in both the progressive reader and the * sequential reader it is necessary to deal with the fact that the progressive * reader callbacks only have one parameter (png_get_progressive_ptr()), so this @@ -4670,114 +4560,6 @@ sequential_row(standard_display *dp, png_structp pp, png_infop pi, png_read_end(pp, pi); } -#ifdef PNG_TEXT_SUPPORTED -static void -standard_check_text(png_const_structp pp, png_const_textp tp, - png_const_charp keyword, png_const_charp text) -{ - char msg[1024]; - size_t pos = safecat(msg, sizeof msg, 0, "text: "); - size_t ok; - - pos = safecat(msg, sizeof msg, pos, keyword); - pos = safecat(msg, sizeof msg, pos, ": "); - ok = pos; - - if (tp->compression != TEXT_COMPRESSION) - { - char buf[64]; - - sprintf(buf, "compression [%d->%d], ", TEXT_COMPRESSION, - tp->compression); - pos = safecat(msg, sizeof msg, pos, buf); - } - - if (tp->key == NULL || strcmp(tp->key, keyword) != 0) - { - pos = safecat(msg, sizeof msg, pos, "keyword \""); - if (tp->key != NULL) - { - pos = safecat(msg, sizeof msg, pos, tp->key); - pos = safecat(msg, sizeof msg, pos, "\", "); - } - - else - pos = safecat(msg, sizeof msg, pos, "null, "); - } - - if (tp->text == NULL) - pos = safecat(msg, sizeof msg, pos, "text lost, "); - - else - { - if (tp->text_length != strlen(text)) - { - char buf[64]; - sprintf(buf, "text length changed[%lu->%lu], ", - (unsigned long)strlen(text), (unsigned long)tp->text_length); - pos = safecat(msg, sizeof msg, pos, buf); - } - - if (strcmp(tp->text, text) != 0) - { - pos = safecat(msg, sizeof msg, pos, "text becomes \""); - pos = safecat(msg, sizeof msg, pos, tp->text); - pos = safecat(msg, sizeof msg, pos, "\" (was \""); - pos = safecat(msg, sizeof msg, pos, text); - pos = safecat(msg, sizeof msg, pos, "\"), "); - } - } - - if (tp->itxt_length != 0) - pos = safecat(msg, sizeof msg, pos, "iTXt length set, "); - - if (tp->lang != NULL) - { - pos = safecat(msg, sizeof msg, pos, "iTXt language \""); - pos = safecat(msg, sizeof msg, pos, tp->lang); - pos = safecat(msg, sizeof msg, pos, "\", "); - } - - if (tp->lang_key != NULL) - { - pos = safecat(msg, sizeof msg, pos, "iTXt keyword \""); - pos = safecat(msg, sizeof msg, pos, tp->lang_key); - pos = safecat(msg, sizeof msg, pos, "\", "); - } - - if (pos > ok) - { - msg[pos-2] = '\0'; /* Remove the ", " at the end */ - png_error(pp, msg); - } -} - -static void -standard_text_validate(standard_display *dp, png_const_structp pp, - png_infop pi) -{ - png_textp tp = NULL; - png_uint_32 num_text = png_get_text(pp, pi, &tp, NULL); - - if (num_text == 2 && tp != NULL) - { - standard_check_text(pp, tp, "image name", dp->ps->current->name); - standard_check_text(pp, tp+1, "end marker", "end"); - } - - else - { - char msg[64]; - - sprintf(msg, "expected two text items, got %lu", - (unsigned long)num_text); - png_error(pp, msg); - } -} -#else -# define standard_text_validate(dp,pp,pi) ((void)0) -#endif - static void standard_row_validate(standard_display *dp, png_const_structp pp, int iImage, int iDisplay, png_uint_32 y) @@ -4809,8 +4591,8 @@ standard_row_validate(standard_display *dp, png_const_structp pp, dp->bit_width)) != 0) { char msg[64]; - sprintf(msg, "PNG image row[%lu][%d] changed from %.2x to %.2x", - (unsigned long)y, where-1, std[where-1], + sprintf(msg, "PNG image row[%d][%d] changed from %.2x to %.2x", y, + where-1, std[where-1], store_image_row(dp->ps, pp, iImage, y)[where-1]); png_error(pp, msg); } @@ -4827,8 +4609,8 @@ standard_row_validate(standard_display *dp, png_const_structp pp, dp->bit_width)) != 0) { char msg[64]; - sprintf(msg, "display row[%lu][%d] changed from %.2x to %.2x", - (unsigned long)y, where-1, std[where-1], + sprintf(msg, "display row[%d][%d] changed from %.2x to %.2x", y, + where-1, std[where-1], store_image_row(dp->ps, pp, iDisplay, y)[where-1]); png_error(pp, msg); } @@ -4865,7 +4647,6 @@ standard_end(png_structp ppIn, png_infop pi) /* Validate the image - progressive reading only produces one variant for * interlaced images. */ - standard_text_validate(dp, pp, pi); standard_image_validate(dp, pp, 0, -1); } @@ -4935,10 +4716,7 @@ standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id, * image is correct. */ if (!d.speed) - { - standard_text_validate(&d, pp, pi); standard_image_validate(&d, pp, 0, 1); - } else d.ps->validated = 1; } @@ -6016,7 +5794,6 @@ image_transform_default_ini(PNG_CONST image_transform *this, this->next->ini(this->next, that); } -#ifdef PNG_READ_BACKGROUND_SUPPORTED static int image_transform_default_add(image_transform *this, PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) @@ -6029,7 +5806,6 @@ image_transform_default_add(image_transform *this, return 1; } -#endif #ifdef PNG_READ_EXPAND_SUPPORTED /* png_set_palette_to_rgb */ @@ -7345,7 +7121,7 @@ perform_transform_test(png_modifier *pm) { png_byte colour_type = 0; png_byte bit_depth = 0; - unsigned int palette_number = 0; + int palette_number = 0; while (next_format(&colour_type, &bit_depth, &palette_number)) { @@ -7708,7 +7484,6 @@ gamma_component_compose(int do_background, double input_sample, double alpha, { switch (do_background) { -#ifdef PNG_READ_BACKGROUND_SUPPORTED case PNG_BACKGROUND_GAMMA_SCREEN: case PNG_BACKGROUND_GAMMA_FILE: case PNG_BACKGROUND_GAMMA_UNIQUE: @@ -7726,7 +7501,6 @@ gamma_component_compose(int do_background, double input_sample, double alpha, input_sample = background; } break; -#endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: @@ -7759,9 +7533,6 @@ gamma_component_compose(int do_background, double input_sample, double alpha, /* Standard cases where no compositing is done (so the component * value is already correct.) */ - UNUSED(alpha) - UNUSED(background) - UNUSED(compose) break; } @@ -8161,13 +7932,11 @@ gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi, */ switch (do_background) { -# ifdef PNG_READ_BACKGROUND_SUPPORTED - case PNG_BACKGROUND_GAMMA_SCREEN: - case PNG_BACKGROUND_GAMMA_FILE: - case PNG_BACKGROUND_GAMMA_UNIQUE: - use_background = (alpha >= 0 && alpha < 1); - /*FALL THROUGH*/ -# endif + case PNG_BACKGROUND_GAMMA_SCREEN: + case PNG_BACKGROUND_GAMMA_FILE: + case PNG_BACKGROUND_GAMMA_UNIQUE: + use_background = (alpha >= 0 && alpha < 1); + /*FALL THROUGH*/ # ifdef PNG_READ_ALPHA_MODE_SUPPORTED case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: @@ -8508,8 +8277,7 @@ gamma_image_validate(gamma_display *dp, png_const_structp pp, char msg[64]; /* No transform is expected on the threshold tests. */ - sprintf(msg, "gamma: below threshold row %lu changed", - (unsigned long)y); + sprintf(msg, "gamma: below threshold row %d changed", y); png_error(pp, msg); } @@ -8714,7 +8482,7 @@ perform_gamma_threshold_tests(png_modifier *pm) { png_byte colour_type = 0; png_byte bit_depth = 0; - unsigned int palette_number = 0; + int palette_number = 0; /* Don't test more than one instance of each palette - it's pointless, in * fact this test is somewhat excessive since libpng doesn't make this @@ -8779,7 +8547,7 @@ static void perform_gamma_transform_tests(png_modifier *pm) { png_byte colour_type = 0; png_byte bit_depth = 0; - unsigned int palette_number = 0; + int palette_number = 0; while (next_format(&colour_type, &bit_depth, &palette_number)) { @@ -8808,8 +8576,11 @@ static void perform_gamma_sbit_tests(png_modifier *pm) */ for (sbit=pm->sbitlow; sbit<(1<<READ_BDHI); ++sbit) { - png_byte colour_type = 0, bit_depth = 0; - unsigned int npalette = 0; + png_byte colour_type, bit_depth; + int npalette; + + colour_type = bit_depth = 0; + npalette = 0; while (next_format(&colour_type, &bit_depth, &npalette)) if ((colour_type & PNG_COLOR_MASK_ALPHA) == 0 && @@ -8895,8 +8666,8 @@ static void perform_gamma_scale16_tests(png_modifier *pm) } #endif /* 16 to 8 bit conversion */ -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) +#if defined PNG_READ_BACKGROUND_SUPPORTED ||\ + defined PNG_READ_ALPHA_MODE_SUPPORTED static void gamma_composition_test(png_modifier *pm, PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth, PNG_CONST int palette_number, @@ -9025,7 +8796,7 @@ perform_gamma_composition_tests(png_modifier *pm, int do_background, { png_byte colour_type = 0; png_byte bit_depth = 0; - unsigned int palette_number = 0; + int palette_number = 0; /* Skip the non-alpha cases - there is no setting of a transparency colour at * present. @@ -9086,9 +8857,7 @@ perform_gamma_test(png_modifier *pm, int summary) /* Save certain values for the temporary overrides below. */ unsigned int calculations_use_input_precision = pm->calculations_use_input_precision; -# ifdef PNG_READ_BACKGROUND_SUPPORTED - double maxout8 = pm->maxout8; -# endif + double maxout8 = pm->maxout8; /* First some arbitrary no-transform tests: */ if (!pm->this.speed && pm->test_gamma_threshold) @@ -9207,7 +8976,6 @@ perform_gamma_test(png_modifier *pm, int summary) #endif } #endif /* PNG_READ_GAMMA_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ /* INTERLACE MACRO VALIDATION */ /* This is copied verbatim from the specification, it is simply the pass @@ -9657,7 +9425,7 @@ static void signal_handler(int signum) } /* main program */ -int main(int argc, char **argv) +int main(int argc, PNG_CONST char **argv) { volatile int summary = 1; /* Print the error summary at the end */ volatile int memstats = 0; /* Print memory statistics at the end */ @@ -10016,9 +9784,7 @@ int main(int argc, char **argv) { perform_interlace_macro_validation(); perform_formatting_test(&pm.this); -# ifdef PNG_READ_SUPPORTED - perform_standard_test(&pm); -# endif + perform_standard_test(&pm); perform_error_test(&pm); } @@ -10026,9 +9792,7 @@ int main(int argc, char **argv) if (pm.test_size) { make_size_images(&pm.this); -# ifdef PNG_READ_SUPPORTED - perform_size_test(&pm); -# endif + perform_size_test(&pm); } #ifdef PNG_READ_TRANSFORMS_SUPPORTED @@ -10121,20 +9885,7 @@ int main(int argc, char **argv) exit(1); } } - - else - { - fprintf(stderr, "%s: open failed\n", touch); - exit(1); - } } return 0; } -#else /* write not supported */ -int main(void) -{ - fprintf(stderr, "pngvalid: no write support in libpng, all tests skipped\n"); - return 0; -} -#endif diff --git a/contrib/libtests/readpng.c b/contrib/libtests/readpng.c deleted file mode 100644 index c5baef53d..000000000 --- a/contrib/libtests/readpng.c +++ /dev/null @@ -1,104 +0,0 @@ -/* readpng.c - * - * Copyright (c) 2013 John Cunningham Bowler - * - * Last changed in libpng 1.6.0 [(PENDING RELEASE)] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * Load an arbitrary number of PNG files (from the command line, or, if there - * are no arguments on the command line, from stdin) then run a time test by - * reading each file by row. The test does nothing with the read result and - * does no transforms. The only output is a time as a floating point number of - * seconds with 9 decimal digits. - */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) -# include <config.h> -#endif - -/* Define the following to use this test against your installed libpng, rather - * than the one being built here: - */ -#ifdef PNG_FREESTANDING_TESTS -# include <png.h> -#else -# include "../../png.h" -#endif - -static int -read_png(FILE *fp) -{ - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); - png_infop info_ptr = NULL; - png_bytep row = NULL, display = NULL; - - if (png_ptr == NULL) - return 0; - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - if (row != NULL) free(row); - if (display != NULL) free(display); - return 0; - } - - png_init_io(png_ptr, fp); - - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - png_error(png_ptr, "OOM allocating info structure"); - - png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); - - png_read_info(png_ptr, info_ptr); - - { - png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); - - row = malloc(rowbytes); - display = malloc(rowbytes); - - if (row == NULL || display == NULL) - png_error(png_ptr, "OOM allocating row buffers"); - - { - png_uint_32 height = png_get_image_height(png_ptr, info_ptr); - int passes = png_set_interlace_handling(png_ptr); - int pass; - - png_start_read_image(png_ptr); - - for (pass = 0; pass < passes; ++pass) - { - png_uint_32 y = height; - - /* NOTE: this trashes the row each time; interlace handling won't - * work, but this avoids memory thrashing for speed testing. - */ - while (y-- > 0) - png_read_row(png_ptr, row, display); - } - } - } - - /* Make sure to read to the end of the file: */ - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - free(row); - free(display); - return 1; -} - -int -main(void) -{ - /* Exit code 0 on success. */ - return !read_png(stdin); -} diff --git a/contrib/libtests/tarith.c b/contrib/libtests/tarith.c deleted file mode 100644 index cdb00dbf7..000000000 --- a/contrib/libtests/tarith.c +++ /dev/null @@ -1,999 +0,0 @@ - -/* tarith.c - * - * Copyright (c) 2011-2013 John Cunningham Bowler - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * Test internal arithmetic functions of libpng. - * - * This code must be linked against a math library (-lm), but does not require - * libpng or zlib to work. Because it includes the complete source of 'png.c' - * it tests the code with whatever compiler options are used to build it. - * Changing these options can substantially change the errors in the - * calculations that the compiler chooses! - */ -#define _POSIX_SOURCE 1 -#define _ISOC99_SOURCE 1 - -/* Obtain a copy of the code to be tested (plus other things), disabling - * stuff that is not required. - */ -#include <math.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> -#include <assert.h> - -#include "../../pngpriv.h" - -#define png_error png_warning - -void png_warning(png_const_structrp png_ptr, png_const_charp msg) -{ - fprintf(stderr, "validation: %s\n", msg); -} - -#define png_fixed_error png_fixed_warning - -void png_fixed_warning(png_const_structrp png_ptr, png_const_charp msg) -{ - fprintf(stderr, "overflow in: %s\n", msg); -} - -#define png_set_error_fn(pp, ep, efp, wfp) ((void)0) -#define png_malloc(pp, s) malloc(s) -#define png_malloc_warn(pp, s) malloc(s) -#define png_malloc_base(pp, s) malloc(s) -#define png_calloc(pp, s) calloc(1, (s)) -#define png_free(pp, s) free(s) - -#define png_safecat(b, sb, pos, str) (pos) -#define png_format_number(start, end, format, number) (start) - -#define crc32(crc, pp, s) (crc) -#define inflateReset(zs) Z_OK - -#define png_create_struct(type) (0) -#define png_destroy_struct(pp) ((void)0) -#define png_create_struct_2(type, m, mm) (0) -#define png_destroy_struct_2(pp, f, mm) ((void)0) - -#undef PNG_SIMPLIFIED_READ_SUPPORTED -#undef PNG_SIMPLIFIED_WRITE_SUPPORTED -#undef PNG_USER_MEM_SUPPORTED - -#include "../../png.c" - -/* Validate ASCII to fp routines. */ -static int verbose = 0; - -int validation_ascii_to_fp(int count, int argc, char **argv) -{ - int showall = 0; - double max_error=2; /* As a percentage error-in-last-digit/.5 */ - double max_error_abs=17; /* Used when precision is DBL_DIG */ - double max = 0; - double max_abs = 0; - double test = 0; /* Important to test this. */ - int precision = 5; - int nonfinite = 0; - int finite = 0; - int ok = 0; - int failcount = 0; - int minorarith = 0; - - while (--argc > 0) - if (strcmp(*++argv, "-a") == 0) - showall = 1; - else if (strcmp(*argv, "-e") == 0 && argc > 0) - { - --argc; - max_error = atof(*++argv); - } - else if (strcmp(*argv, "-E") == 0 && argc > 0) - { - --argc; - max_error_abs = atof(*++argv); - } - else - { - fprintf(stderr, "unknown argument %s\n", *argv); - return 1; - } - - do - { - png_size_t index; - int state, failed = 0; - char buffer[64]; - - if (isfinite(test)) - ++finite; - else - ++nonfinite; - - if (verbose) - fprintf(stderr, "%.*g %d\n", DBL_DIG, test, precision); - - /* Check for overflow in the buffer by setting a marker. */ - memset(buffer, 71, sizeof buffer); - - png_ascii_from_fp(0, buffer, precision+10, test, precision); - - /* Allow for a three digit exponent, this stuff will fail if - * the exponent is bigger than this! - */ - if (buffer[precision+7] != 71) - { - fprintf(stderr, "%g[%d] -> '%s'[%lu] buffer overflow\n", test, - precision, buffer, (unsigned long)strlen(buffer)); - failed = 1; - } - - /* Following are used for the number parser below and must be - * initialized to zero. - */ - state = 0; - index = 0; - if (!isfinite(test)) - { - /* Expect 'inf' */ - if (test >= 0 && strcmp(buffer, "inf") || - test < 0 && strcmp(buffer, "-inf")) - { - fprintf(stderr, "%g[%d] -> '%s' but expected 'inf'\n", test, - precision, buffer); - failed = 1; - } - } - else if (!png_check_fp_number(buffer, precision+10, &state, &index) || - buffer[index] != 0) - { - fprintf(stderr, "%g[%d] -> '%s' but has bad format ('%c')\n", test, - precision, buffer, buffer[index]); - failed = 1; - } - else if (PNG_FP_IS_NEGATIVE(state) && !(test < 0)) - { - fprintf(stderr, "%g[%d] -> '%s' but negative value not so reported\n", - test, precision, buffer); - failed = 1; - assert(!PNG_FP_IS_ZERO(state)); - assert(!PNG_FP_IS_POSITIVE(state)); - } - else if (PNG_FP_IS_ZERO(state) && !(test == 0)) - { - fprintf(stderr, "%g[%d] -> '%s' but zero value not so reported\n", - test, precision, buffer); - failed = 1; - assert(!PNG_FP_IS_NEGATIVE(state)); - assert(!PNG_FP_IS_POSITIVE(state)); - } - else if (PNG_FP_IS_POSITIVE(state) && !(test > 0)) - { - fprintf(stderr, "%g[%d] -> '%s' but postive value not so reported\n", - test, precision, buffer); - failed = 1; - assert(!PNG_FP_IS_NEGATIVE(state)); - assert(!PNG_FP_IS_ZERO(state)); - } - else - { - /* Check the result against the original. */ - double out = atof(buffer); - double change = fabs((out - test)/test); - double allow = .5/pow(10, - (precision >= DBL_DIG) ? DBL_DIG-1 : precision-1); - - /* NOTE: if you hit this error case are you compiling with gcc - * and -O0? Try -O2 - the errors can accumulate if the FP - * code above is not optimized and may drift outside the .5 in - * DBL_DIG allowed. In any case a small number of errors may - * occur (very small ones - 1 or 2%) because of rounding in the - * calculations, either in the conversion API or in atof. - */ - if (change >= allow && (isfinite(out) || - fabs(test/DBL_MAX) <= 1-allow)) - { - double percent = (precision >= DBL_DIG) ? max_error_abs : max_error; - double allowp = (change-allow)*100/allow; - - if (precision >= DBL_DIG) - { - if (max_abs < allowp) max_abs = allowp; - } - - else - { - if (max < allowp) max = allowp; - } - - if (showall || allowp >= percent) - { - fprintf(stderr, - "%.*g[%d] -> '%s' -> %.*g number changed (%g > %g (%d%%))\n", - DBL_DIG, test, precision, buffer, DBL_DIG, out, change, allow, - (int)round(allowp)); - failed = 1; - } - else - ++minorarith; - } - } - - if (failed) - ++failcount; - else - ++ok; - -skip: - /* Generate a new number and precision. */ - precision = rand(); - if (precision & 1) test = -test; - precision >>= 1; - - /* Generate random numbers. */ - if (test == 0 || !isfinite(test)) - test = precision+1; - else - { - /* Derive the exponent from the previous rand() value. */ - int exponent = precision % (DBL_MAX_EXP - DBL_MIN_EXP) + DBL_MIN_EXP; - int tmp; - test = frexp(test * rand(), &tmp); - test = ldexp(test, exponent); - precision >>= 8; /* arbitrary */ - } - - /* This limits the precision to 32 digits, enough for standard - * IEEE implementations which have at most 15 digits. - */ - precision = (precision & 0x1f) + 1; - } - while (--count); - - printf("Tested %d finite values, %d non-finite, %d OK (%d failed) %d minor " - "arithmetic errors\n", finite, nonfinite, ok, failcount, minorarith); - printf(" Error with >=%d digit precision %.2f%%\n", DBL_DIG, max_abs); - printf(" Error with < %d digit precision %.2f%%\n", DBL_DIG, max); - - return 0; -} - -/* Observe that valid FP numbers have the forms listed in the PNG extensions - * specification: - * - * [+,-]{integer,integer.fraction,.fraction}[{e,E}[+,-]integer] - * - * Test each of these in turn, including invalid cases. - */ -typedef enum checkfp_state -{ - start, fraction, exponent, states -} checkfp_state; - -/* The characters (other than digits) that characterize the states: */ -static const char none[] = ""; -static const char hexdigits[16] = "0123456789ABCDEF"; - -static const struct -{ - const char *start; /* Characters valid at the start */ - const char *end; /* Valid characters that end the state */ - const char *tests; /* Characters to test after 2 digits seen */ -} -state_characters[states] = -{ - /* start: */ { "+-.", ".eE", "+-.e*0369" }, - /* fraction: */ { none, "eE", "+-.E#0147" }, - /* exponent: */ { "+-", none, "+-.eE^0258" } -}; - -typedef struct -{ - char number[1024]; /* Buffer for number being tested */ - int limit; /* Command line limit */ - int verbose; /* Shadows global variable */ - int ctimes; /* Number of numbers tested */ - int cmillions; /* Count of millions of numbers */ - int cinvalid; /* Invalid strings checked */ - int cnoaccept; /* Characters not accepted */ -} -checkfp_command; - -typedef struct -{ - int cnumber; /* Index into number string */ - checkfp_state check_state; /* Current number state */ - int at_start; /* At start (first character) of state */ - int cdigits_in_state; /* Digits seen in that state */ - int limit; /* Limit on same for checking all chars */ - int state; /* Current parser state */ - int is_negative; /* Number is negative */ - int is_zero; /* Number is (still) zero */ - int number_was_valid; /* Previous character validity */ -} -checkfp_control; - -static int check_all_characters(checkfp_command *co, checkfp_control c); - -static int check_some_characters(checkfp_command *co, checkfp_control c, - const char *tests); - -static int check_one_character(checkfp_command *co, checkfp_control c, int ch) -{ - /* Test this character (ch) to ensure the parser does the correct thing. - */ - png_size_t index = 0; - const char test = (char)ch; - const int number_is_valid = png_check_fp_number(&test, 1, &c.state, &index); - const int character_accepted = (index == 1); - - if (c.check_state != exponent && isdigit(ch) && ch != '0') - c.is_zero = 0; - - if (c.check_state == start && c.at_start && ch == '-') - c.is_negative = 1; - - if (isprint(ch)) - co->number[c.cnumber++] = (char)ch; - else - { - co->number[c.cnumber++] = '<'; - co->number[c.cnumber++] = hexdigits[(ch >> 4) & 0xf]; - co->number[c.cnumber++] = hexdigits[ch & 0xf]; - co->number[c.cnumber++] = '>'; - } - co->number[c.cnumber] = 0; - - if (co->verbose > 1) - fprintf(stderr, "%s\n", co->number); - - if (++(co->ctimes) == 1000000) - { - if (co->verbose == 1) - fputc('.', stderr); - co->ctimes = 0; - ++(co->cmillions); - } - - if (!number_is_valid) - ++(co->cinvalid); - - if (!character_accepted) - ++(co->cnoaccept); - - /* This should never fail (it's a serious bug if it does): */ - if (index != 0 && index != 1) - { - fprintf(stderr, "%s: read beyond end of string (%lu)\n", co->number, - (unsigned long)index); - return 0; - } - - /* Validate the new state, note that the PNG_FP_IS_ macros all return - * false unless the number is valid. - */ - if (PNG_FP_IS_NEGATIVE(c.state) != - (number_is_valid && !c.is_zero && c.is_negative)) - { - fprintf(stderr, "%s: negative when it is not\n", co->number); - return 0; - } - - if (PNG_FP_IS_ZERO(c.state) != (number_is_valid && c.is_zero)) - { - fprintf(stderr, "%s: zero when it is not\n", co->number); - return 0; - } - - if (PNG_FP_IS_POSITIVE(c.state) != - (number_is_valid && !c.is_zero && !c.is_negative)) - { - fprintf(stderr, "%s: positive when it is not\n", co->number); - return 0; - } - - /* Testing a digit */ - if (isdigit(ch)) - { - if (!character_accepted) - { - fprintf(stderr, "%s: digit '%c' not accepted\n", co->number, ch); - return 0; - } - - if (!number_is_valid) - { - fprintf(stderr, "%s: saw a digit (%c) but number not valid\n", - co->number, ch); - return 0; - } - - ++c.cdigits_in_state; - c.at_start = 0; - c.number_was_valid = 1; - - /* Continue testing characters in this state. Either test all of - * them or, if we have already seen one digit in this state, just test a - * limited set. - */ - if (c.cdigits_in_state < 1) - return check_all_characters(co, c); - - else - return check_some_characters(co, c, - state_characters[c.check_state].tests); - } - - /* A non-digit; is it allowed here? */ - else if (((ch == '+' || ch == '-') && c.check_state != fraction && - c.at_start) || - (ch == '.' && c.check_state == start) || - ((ch == 'e' || ch == 'E') && c.number_was_valid && - c.check_state != exponent)) - { - if (!character_accepted) - { - fprintf(stderr, "%s: character '%c' not accepted\n", co->number, ch); - return 0; - } - - /* The number remains valid after start of fraction but nowhere else. */ - if (number_is_valid && (c.check_state != start || ch != '.')) - { - fprintf(stderr, "%s: saw a non-digit (%c) but number valid\n", - co->number, ch); - return 0; - } - - c.number_was_valid = number_is_valid; - - /* Check for a state change. When changing to 'fraction' if the number - * is valid at this point set the at_start to false to allow an exponent - * 'e' to come next. - */ - if (c.check_state == start && ch == '.') - { - c.check_state = fraction; - c.at_start = !number_is_valid; - c.cdigits_in_state = 0; - c.limit = co->limit; - return check_all_characters(co, c); - } - - else if (c.check_state < exponent && (ch == 'e' || ch == 'E')) - { - c.check_state = exponent; - c.at_start = 1; - c.cdigits_in_state = 0; - c.limit = co->limit; - return check_all_characters(co, c); - } - - /* Else it was a sign, and the state doesn't change. */ - else - { - if (ch != '-' && ch != '+') - { - fprintf(stderr, "checkfp: internal error (1)\n"); - return 0; - } - - c.at_start = 0; - return check_all_characters(co, c); - } - } - - /* Testing an invalid character */ - else - { - if (character_accepted) - { - fprintf(stderr, "%s: character '%c' [0x%.2x] accepted\n", co->number, - ch, ch); - return 0; - } - - if (number_is_valid != c.number_was_valid) - { - fprintf(stderr, - "%s: character '%c' [0x%.2x] changed number validity\n", co->number, - ch, ch); - return 0; - } - - /* Do nothing - the parser has stuck; return success and keep going with - * the next character. - */ - } - - /* Successful return (the caller will try the next character.) */ - return 1; -} - -static int check_all_characters(checkfp_command *co, checkfp_control c) -{ - int ch; - - if (c.cnumber+4 < sizeof co->number) for (ch=0; ch<256; ++ch) - { - if (!check_one_character(co, c, ch)) - return 0; - } - - return 1; -} - -static int check_some_characters(checkfp_command *co, checkfp_control c, - const char *tests) -{ - int i; - - --(c.limit); - - if (c.cnumber+4 < sizeof co->number && c.limit >= 0) - { - if (c.limit > 0) for (i=0; tests[i]; ++i) - { - if (!check_one_character(co, c, tests[i])) - return 0; - } - - /* At the end check all the characters. */ - else - return check_all_characters(co, c); - } - - return 1; -} - -int validation_checkfp(int count, int argc, char **argv) -{ - int result; - checkfp_command command; - checkfp_control control; - - command.number[0] = 0; - command.limit = 3; - command.verbose = verbose; - command.ctimes = 0; - command.cmillions = 0; - command.cinvalid = 0; - command.cnoaccept = 0; - - while (--argc > 0) - { - ++argv; - if (argc > 1 && strcmp(*argv, "-l") == 0) - { - --argc; - command.limit = atoi(*++argv); - } - - else - { - fprintf(stderr, "unknown argument %s\n", *argv); - return 1; - } - } - - control.cnumber = 0; - control.check_state = start; - control.at_start = 1; - control.cdigits_in_state = 0; - control.limit = command.limit; - control.state = 0; - control.is_negative = 0; - control.is_zero = 1; - control.number_was_valid = 0; - - result = check_all_characters(&command, control); - - printf("checkfp: %s: checked %d,%.3d,%.3d,%.3d strings (%d invalid)\n", - result ? "pass" : "FAIL", command.cmillions / 1000, - command.cmillions % 1000, command.ctimes / 1000, command.ctimes % 1000, - command.cinvalid); - - return result; -} - -int validation_muldiv(int count, int argc, char **argv) -{ - int tested = 0; - int overflow = 0; - int error = 0; - int error64 = 0; - int passed = 0; - int randbits = 0; - png_uint_32 randbuffer; - png_fixed_point a; - png_int_32 times, div; - - while (--argc > 0) - { - fprintf(stderr, "unknown argument %s\n", *++argv); - return 1; - } - - /* Find out about the random number generator. */ - randbuffer = RAND_MAX; - while (randbuffer != 0) ++randbits, randbuffer >>= 1; - printf("Using random number generator that makes %d bits\n", randbits); - for (div=0; div<32; div += randbits) - randbuffer = (randbuffer << randbits) ^ rand(); - - a = 0; - times = div = 0; - do - { - png_fixed_point result; - /* NOTE: your mileage may vary, a type is required below that can - * hold 64 bits or more, if floating point is used a 64 bit or - * better mantissa is required. - */ - long long int fp, fpround; - unsigned long hi, lo; - int ok; - - /* Check the values, png_64bit_product can only handle positive - * numbers, so correct for that here. - */ - { - long u1, u2; - int n = 0; - if (a < 0) u1 = -a, n = 1; else u1 = a; - if (times < 0) u2 = -times, n = !n; else u2 = times; - png_64bit_product(u1, u2, &hi, &lo); - if (n) - { - /* -x = ~x+1 */ - lo = ((~lo) + 1) & 0xffffffff; - hi = ~hi; - if (lo == 0) ++hi; - } - } - - fp = a; - fp *= times; - if ((fp & 0xffffffff) != lo || ((fp >> 32) & 0xffffffff) != hi) - { - fprintf(stderr, "png_64bit_product %d * %d -> %lx|%.8lx not %llx\n", - a, times, hi, lo, fp); - ++error64; - } - - if (div != 0) - { - /* Round - this is C round to zero. */ - if ((fp < 0) != (div < 0)) - fp -= div/2; - else - fp += div/2; - - fp /= div; - fpround = fp; - /* Assume 2's complement here: */ - ok = fpround <= PNG_UINT_31_MAX && - fpround >= -1-(long long int)PNG_UINT_31_MAX; - if (!ok) ++overflow; - } - else - ok = 0, ++overflow, fpround = fp/*misleading*/; - - if (verbose) - fprintf(stderr, "TEST %d * %d / %d -> %lld (%s)\n", a, times, div, - fp, ok ? "ok" : "overflow"); - - ++tested; - if (png_muldiv(&result, a, times, div) != ok) - { - ++error; - if (ok) - fprintf(stderr, "%d * %d / %d -> overflow (expected %lld)\n", a, - times, div, fp); - else - fprintf(stderr, "%d * %d / %d -> %d (expected overflow %lld)\n", a, - times, div, result, fp); - } - else if (ok && result != fpround) - { - ++error; - fprintf(stderr, "%d * %d / %d -> %d not %lld\n", a, times, div, result, - fp); - } - else - ++passed; - - /* Generate three new values, this uses rand() and rand() only returns - * up to RAND_MAX. - */ - /* CRUDE */ - a += times; - times += div; - div = randbuffer; - randbuffer = (randbuffer << randbits) ^ rand(); - } - while (--count > 0); - - printf("%d tests including %d overflows, %d passed, %d failed (%d 64 bit " - "errors)\n", tested, overflow, passed, error, error64); - return 0; -} - -/* When FP is on this just becomes a speed test - compile without FP to get real - * validation. - */ -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED -#define LN2 .000010576586617430806112933839 /* log(2)/65536 */ -#define L2INV 94548.46219969910586572651 /* 65536/log(2) */ - -/* For speed testing, need the internal functions too: */ -static png_uint_32 png_log8bit(unsigned x) -{ - if (x > 0) - return (png_uint_32)floor(.5-log(x/255.)*L2INV); - - return 0xffffffff; -} - -static png_uint_32 png_log16bit(png_uint_32 x) -{ - if (x > 0) - return (png_uint_32)floor(.5-log(x/65535.)*L2INV); - - return 0xffffffff; -} - -static png_uint_32 png_exp(png_uint_32 x) -{ - return (png_uint_32)floor(.5 + exp(x * -LN2) * 0xffffffffU); -} - -static png_byte png_exp8bit(png_uint_32 log) -{ - return (png_byte)floor(.5 + exp(log * -LN2) * 255); -} - -static png_uint_16 png_exp16bit(png_uint_32 log) -{ - return (png_uint_16)floor(.5 + exp(log * -LN2) * 65535); -} -#endif /* FLOATING_ARITHMETIC */ - -int validation_gamma(int argc, char **argv) -{ - double gamma[9] = { 2.2, 1.8, 1.52, 1.45, 1., 1/1.45, 1/1.52, 1/1.8, 1/2.2 }; - double maxerr; - int i, silent=0, onlygamma=0; - - /* Silence the output with -s, just test the gamma functions with -g: */ - while (--argc > 0) - if (strcmp(*++argv, "-s") == 0) - silent = 1; - else if (strcmp(*argv, "-g") == 0) - onlygamma = 1; - else - { - fprintf(stderr, "unknown argument %s\n", *argv); - return 1; - } - - if (!onlygamma) - { - /* First validate the log functions: */ - maxerr = 0; - for (i=0; i<256; ++i) - { - double correct = -log(i/255.)/log(2.)*65536; - double error = png_log8bit(i) - correct; - - if (i != 0 && fabs(error) > maxerr) - maxerr = fabs(error); - - if (i == 0 && png_log8bit(i) != 0xffffffff || - i != 0 && png_log8bit(i) != floor(correct+.5)) - { - fprintf(stderr, "8 bit log error: %d: got %u, expected %f\n", - i, png_log8bit(i), correct); - } - } - - if (!silent) - printf("maximum 8 bit log error = %f\n", maxerr); - - maxerr = 0; - for (i=0; i<65536; ++i) - { - double correct = -log(i/65535.)/log(2.)*65536; - double error = png_log16bit(i) - correct; - - if (i != 0 && fabs(error) > maxerr) - maxerr = fabs(error); - - if (i == 0 && png_log16bit(i) != 0xffffffff || - i != 0 && png_log16bit(i) != floor(correct+.5)) - { - if (error > .68) /* By experiment error is less than .68 */ - { - fprintf(stderr, "16 bit log error: %d: got %u, expected %f" - " error: %f\n", i, png_log16bit(i), correct, error); - } - } - } - - if (!silent) - printf("maximum 16 bit log error = %f\n", maxerr); - - /* Now exponentiations. */ - maxerr = 0; - for (i=0; i<=0xfffff; ++i) - { - double correct = exp(-i/65536. * log(2.)) * (65536. * 65536); - double error = png_exp(i) - correct; - - if (fabs(error) > maxerr) - maxerr = fabs(error); - if (fabs(error) > 1883) /* By experiment. */ - { - fprintf(stderr, "32 bit exp error: %d: got %u, expected %f" - " error: %f\n", i, png_exp(i), correct, error); - } - } - - if (!silent) - printf("maximum 32 bit exp error = %f\n", maxerr); - - maxerr = 0; - for (i=0; i<=0xfffff; ++i) - { - double correct = exp(-i/65536. * log(2.)) * 255; - double error = png_exp8bit(i) - correct; - - if (fabs(error) > maxerr) - maxerr = fabs(error); - if (fabs(error) > .50002) /* By experiment */ - { - fprintf(stderr, "8 bit exp error: %d: got %u, expected %f" - " error: %f\n", i, png_exp8bit(i), correct, error); - } - } - - if (!silent) - printf("maximum 8 bit exp error = %f\n", maxerr); - - maxerr = 0; - for (i=0; i<=0xfffff; ++i) - { - double correct = exp(-i/65536. * log(2.)) * 65535; - double error = png_exp16bit(i) - correct; - - if (fabs(error) > maxerr) - maxerr = fabs(error); - if (fabs(error) > .524) /* By experiment */ - { - fprintf(stderr, "16 bit exp error: %d: got %u, expected %f" - " error: %f\n", i, png_exp16bit(i), correct, error); - } - } - - if (!silent) - printf("maximum 16 bit exp error = %f\n", maxerr); - } /* !onlygamma */ - - /* Test the overall gamma correction. */ - for (i=0; i<9; ++i) - { - unsigned j; - double g = gamma[i]; - png_fixed_point gfp = floor(g * PNG_FP_1 + .5); - - if (!silent) - printf("Test gamma %f\n", g); - - maxerr = 0; - for (j=0; j<256; ++j) - { - double correct = pow(j/255., g) * 255; - png_byte out = png_gamma_8bit_correct(j, gfp); - double error = out - correct; - - if (fabs(error) > maxerr) - maxerr = fabs(error); - if (out != floor(correct+.5)) - { - fprintf(stderr, "8bit %d ^ %f: got %d expected %f error %f\n", - j, g, out, correct, error); - } - } - - if (!silent) - printf("gamma %f: maximum 8 bit error %f\n", g, maxerr); - - maxerr = 0; - for (j=0; j<65536; ++j) - { - double correct = pow(j/65535., g) * 65535; - png_uint_16 out = png_gamma_16bit_correct(j, gfp); - double error = out - correct; - - if (fabs(error) > maxerr) - maxerr = fabs(error); - if (fabs(error) > 1.62) - { - fprintf(stderr, "16bit %d ^ %f: got %d expected %f error %f\n", - j, g, out, correct, error); - } - } - - if (!silent) - printf("gamma %f: maximum 16 bit error %f\n", g, maxerr); - } - - return 0; -} - -/**************************** VALIDATION TESTS ********************************/ -/* Various validation routines are included herein, they require some - * definition for png_warning and png_error, seetings of VALIDATION: - * - * 1: validates the ASCII to floating point conversions - * 2: validates png_muldiv - * 3: accuracy test of fixed point gamma tables - */ - -/* The following COUNT (10^8) takes about 1 hour on a 1GHz Pentium IV - * processor. - */ -#define COUNT 1000000000 - -int main(int argc, char **argv) -{ - int count = COUNT; - - while (argc > 1) - { - if (argc > 2 && strcmp(argv[1], "-c") == 0) - { - count = atoi(argv[2]); - argc -= 2; - argv += 2; - } - - else if (strcmp(argv[1], "-v") == 0) - { - ++verbose; - --argc; - ++argv; - } - - else - break; - } - - if (count > 0 && argc > 1) - { - if (strcmp(argv[1], "ascii") == 0) - return validation_ascii_to_fp(count, argc-1, argv+1); - else if (strcmp(argv[1], "checkfp") == 0) - return validation_checkfp(count, argc-1, argv+1); - else if (strcmp(argv[1], "muldiv") == 0) - return validation_muldiv(count, argc-1, argv+1); - else if (strcmp(argv[1], "gamma") == 0) - return validation_gamma(argc-1, argv+1); - } - - /* Bad argument: */ - fprintf(stderr, - "usage: tarith [-v] [-c count] {ascii,muldiv,gamma} [args]\n"); - fprintf(stderr, " arguments: ascii [-a (all results)] [-e error%%]\n"); - fprintf(stderr, " checkfp [-l max-number-chars]\n"); - fprintf(stderr, " muldiv\n"); - fprintf(stderr, " gamma -s (silent) -g (only gamma; no log)\n"); - return 1; -} diff --git a/contrib/libtests/timepng.c b/contrib/libtests/timepng.c index 3469afeb6..4d5780428 100644 --- a/contrib/libtests/timepng.c +++ b/contrib/libtests/timepng.c @@ -1,8 +1,8 @@ /* timepng.c * - * Copyright (c) 2013 John Cunningham Bowler + * Copyright (c) 2012 John Cunningham Bowler * - * Last changed in libpng 1.6.0 [February 14, 2013] + * Last changed in libpng 1.6.0 [(PENDING RELEASE)] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -22,7 +22,7 @@ #include <time.h> -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +#if (defined HAVE_CONFIG_H) && !(defined PNG_NO_CONFIG_H) # include <config.h> #endif diff --git a/contrib/pngminim/decoder/makefile b/contrib/pngminim/decoder/makefile index dafba64b7..e10e1225d 100644 --- a/contrib/pngminim/decoder/makefile +++ b/contrib/pngminim/decoder/makefile @@ -14,7 +14,7 @@ LD=$(CC) RM=rm -f COPY=cp -CFLAGS=-DPNG_USER_CONFIG -DNO_GZCOMPRESS -DZ_SOLO -DNO_GZIP -I. -O1 +CFLAGS=-DPNG_USER_CONFIG -DNO_GZCOMPRESS -DNO_GZIP -I. -O1 C=.c O=.o diff --git a/contrib/pngminim/decoder/pngusr.dfa b/contrib/pngminim/decoder/pngusr.dfa index 4f402721a..70d528bc9 100644 --- a/contrib/pngminim/decoder/pngusr.dfa +++ b/contrib/pngminim/decoder/pngusr.dfa @@ -1,6 +1,6 @@ # pngminim/decoder/pngusr.dfa # -# Copyright (c) 2010-2013 Glenn Randers-Pehrson +# Copyright (c) 2010-2011 Glenn Randers-Pehrson # # This code is released under the libpng license. # For conditions of distribution and use, see the disclaimer @@ -37,4 +37,3 @@ option SETJMP on option STDIO on option READ_EXPAND on option READ_STRIP_16_TO_8 on -option USER_LIMITS on diff --git a/contrib/pngminim/decoder/pngusr.h b/contrib/pngminim/decoder/pngusr.h index 841da0c28..9d9c50c40 100644 --- a/contrib/pngminim/decoder/pngusr.h +++ b/contrib/pngminim/decoder/pngusr.h @@ -1,6 +1,6 @@ /* minrdpngconf.h: headers to make a minimal png-read-only library * - * Copyright (c) 2007, 2010-2013 Glenn Randers-Pehrson + * Copyright (c) 2007, 2010-2011 Glenn Randers-Pehrson * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer diff --git a/contrib/pngminim/encoder/README b/contrib/pngminim/encoder/README index d8d9a6466..ff9aa4597 100644 --- a/contrib/pngminim/encoder/README +++ b/contrib/pngminim/encoder/README @@ -1,6 +1,6 @@ This demonstrates the use of PNG_USER_CONFIG and pngusr.h -The makefile builds a minimal write-only encoder with embedded libpng +The makefile builds a minimal write-only decoder with embedded libpng and zlib. Specify the location of the zlib source (1.2.1 or later) as ZLIBSRC diff --git a/contrib/pngminim/encoder/makefile b/contrib/pngminim/encoder/makefile index 810b8c8fa..d6f39e2ea 100644 --- a/contrib/pngminim/encoder/makefile +++ b/contrib/pngminim/encoder/makefile @@ -14,7 +14,7 @@ LD=$(CC) RM=rm -f COPY=cp -CFLAGS=-DPNG_USER_CONFIG -DZ_SOLO -DNO_GZIP -I. -O1 +CFLAGS=-DPNG_USER_CONFIG -DNO_GZIP -I. -O1 C=.c O=.o diff --git a/contrib/pngminim/encoder/pngusr.dfa b/contrib/pngminim/encoder/pngusr.dfa index 88d8b2a07..ee88443c9 100644 --- a/contrib/pngminim/encoder/pngusr.dfa +++ b/contrib/pngminim/encoder/pngusr.dfa @@ -1,6 +1,6 @@ # pngminim/encoder/pngusr.dfa # -# Copyright (c) 2010-2013 Glenn Randers-Pehrson +# Copyright (c) 2010-2011 Glenn Randers-Pehrson # # This code is released under the libpng license. # For conditions of distribution and use, see the disclaimer diff --git a/contrib/pngminim/encoder/pngusr.h b/contrib/pngminim/encoder/pngusr.h index a050ef3eb..2033aadb2 100644 --- a/contrib/pngminim/encoder/pngusr.h +++ b/contrib/pngminim/encoder/pngusr.h @@ -1,6 +1,6 @@ /* minwrpngconf.h: headers to make a minimal png-write-only library * - * Copyright (c) 2007, 2010-2013 Glenn Randers-Pehrson + * Copyright (c) 2007, 2010-2011 Glenn Randers-Pehrson * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer diff --git a/contrib/pngminim/preader/makefile b/contrib/pngminim/preader/makefile index ecc05c7bf..f4b0ccdc8 100644 --- a/contrib/pngminim/preader/makefile +++ b/contrib/pngminim/preader/makefile @@ -30,7 +30,7 @@ XLIB = -L/usr/X11R6/lib -lX11 #LIBS = $(XLIB) LIBS = $(XLIB) -lm #platforms that need libm -CFLAGS=-DPNG_USER_CONFIG -DNO_GZCOMPRESS -DZ_SOLO -DNO_GZIP -I. $(XINC) -O1 +CFLAGS=-DPNG_USER_CONFIG -DNO_GZCOMPRESS -DNO_GZIP -I. $(XINC) -O1 C=.c O=.o diff --git a/contrib/pngminim/preader/pngusr.dfa b/contrib/pngminim/preader/pngusr.dfa index ac297f41b..216c421ca 100644 --- a/contrib/pngminim/preader/pngusr.dfa +++ b/contrib/pngminim/preader/pngusr.dfa @@ -1,6 +1,6 @@ # pngminim/preader/pngusr.dfa # -# Copyright (c) 2010-2013 Glenn Randers-Pehrson +# Copyright (c) 2010-2011 Glenn Randers-Pehrson # # This code is released under the libpng license. # For conditions of distribution and use, see the disclaimer diff --git a/contrib/pngminim/preader/pngusr.h b/contrib/pngminim/preader/pngusr.h index d84863472..73cfecfbf 100644 --- a/contrib/pngminim/preader/pngusr.h +++ b/contrib/pngminim/preader/pngusr.h @@ -1,6 +1,6 @@ /* minrdpngconf.h: headers to make a minimal png-read-only library * - * Copyright (c) 2009, 2010-2013 Glenn Randers-Pehrson + * Copyright (c) 2009, 2010-2011 Glenn Randers-Pehrson * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer diff --git a/contrib/pngminus/pnm2png.c b/contrib/pngminus/pnm2png.c index d098e33cb..a44436717 100644 --- a/contrib/pngminus/pnm2png.c +++ b/contrib/pngminus/pnm2png.c @@ -239,7 +239,7 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, get_token(pnm_file, maxval_token); sscanf (maxval_token, "%lu", &ul_maxval); maxval = (png_uint_32) ul_maxval; - + if (maxval <= 1) bit_depth = 1; else if (maxval <= 3) diff --git a/contrib/pngsuite/README b/contrib/pngsuite/README index ec4af9473..b2b1537db 100644 --- a/contrib/pngsuite/README +++ b/contrib/pngsuite/README @@ -1,8 +1,7 @@ pngsuite -------- -(c) Willem van Schaik, 1999, 2011, 2012 -Two images are by Glenn Randers-Pehrson, 2012 +(c) Willem van Schaik, 1999, 2011 Permission to use, copy, modify, and distribute these images for any purpose and without fee is hereby granted. @@ -39,8 +38,6 @@ can use them to test the proper functioning of PNG software. basn6a08.png 8-bit RGBA basn6a16.png 16-bit RGBA - ftbbn0g01.png 1-bit grayscale, black bKGD - ftbbn0g02.png 2-bit grayscale, black bKGD ftbbn0g04.png 4-bit grayscale, black bKGD ftbbn2c16.png 16-bit truecolor, black bKGD ftbbn3p08.png 8-bit paletted, black bKGD diff --git a/contrib/pngsuite/ftbbn0g01.png b/contrib/pngsuite/ftbbn0g01.png Binary files differdeleted file mode 100644 index ba746ffb2..000000000 --- a/contrib/pngsuite/ftbbn0g01.png +++ /dev/null diff --git a/contrib/pngsuite/ftbbn0g02.png b/contrib/pngsuite/ftbbn0g02.png Binary files differdeleted file mode 100644 index 3d83bd690..000000000 --- a/contrib/pngsuite/ftbbn0g02.png +++ /dev/null diff --git a/contrib/pngsuite/ftbbn0g04.png b/contrib/pngsuite/ftbbn1g04.png Binary files differindex 39a7050d2..39a7050d2 100644 --- a/contrib/pngsuite/ftbbn0g04.png +++ b/contrib/pngsuite/ftbbn1g04.png diff --git a/contrib/pngsuite/ftbwn0g16.png b/contrib/pngsuite/ftbwn1g16.png Binary files differindex 99bdeed2b..99bdeed2b 100644 --- a/contrib/pngsuite/ftbwn0g16.png +++ b/contrib/pngsuite/ftbwn1g16.png diff --git a/contrib/pngsuite/ftp0n0g08.png b/contrib/pngsuite/ftp0n1g08.png Binary files differindex 333465fcd..333465fcd 100644 --- a/contrib/pngsuite/ftp0n0g08.png +++ b/contrib/pngsuite/ftp0n1g08.png diff --git a/contrib/tools/checksum-icc.c b/contrib/tools/checksum-icc.c deleted file mode 100644 index 581e7088a..000000000 --- a/contrib/tools/checksum-icc.c +++ /dev/null @@ -1,102 +0,0 @@ -/* checksum-icc.c - * - * Copyright (c) 2013 John Cunningham Bowler - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * Generate crc32 and adler32 checksums of the given input files, used to - * generate check-codes for use when matching ICC profiles within libpng. - */ -#include <stdio.h> - -#include <zlib.h> - -static int -read_one_file(FILE *ip, const char *name) -{ - uLong length = 0; - uLong a32 = adler32(0, NULL, 0); - uLong c32 = crc32(0, NULL, 0); - Byte header[132]; - - for (;;) - { - int ch = getc(ip); - Byte b; - - if (ch == EOF) break; - - b = (Byte)ch; - - if (length < sizeof header) - header[length] = b; - - ++length; - a32 = adler32(a32, &b, 1); - c32 = crc32(c32, &b, 1); - } - - if (ferror(ip)) - return 0; - - /* Success */ - printf("PNG_ICC_CHECKSUM(0x%8.8lx, 0x%8.8lx,\n PNG_MD5(" - "0x%2.2x%2.2x%2.2x%2.2x, 0x%2.2x%2.2x%2.2x%2.2x, 0x%2.2x%2.2x%2.2x%2.2x," - " 0x%2.2x%2.2x%2.2x%2.2x), %d,\n" - " \"%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d\", %lu, \"%s\")\n", - (unsigned long)a32, (unsigned long)c32, - header[84], header[85], header[86], header[87], - header[88], header[89], header[90], header[91], - header[92], header[93], header[94], header[95], - header[96], header[97], header[98], header[99], -# define u16(x) (header[x] * 256 + header[x+1]) -# define u32(x) (u16(x) * 65536 + u16(x+2)) - u32(64), u16(24), u16(26), u16(28), u16(30), u16(32), u16(34), - (unsigned long)length, name); - - return 1; -} - -int main(int argc, char **argv) -{ - int err = 0; - - printf("/* adler32, crc32, MD5[16], intent, date, length, file-name */\n"); - - if (argc > 1) - { - int i; - - for (i=1; i<argc; ++i) - { - FILE *ip = fopen(argv[i], "rb"); - - if (ip == NULL || !read_one_file(ip, argv[i])) - { - err = 1; - perror(argv[i]); - fprintf(stderr, "%s: read error\n", argv[i]); - printf("/* ERROR: %s */\n", argv[i]); - } - - (void)fclose(ip); - } - } - - else - { - if (!read_one_file(stdin, "-")) - { - err = 1; - perror("stdin"); - fprintf(stderr, "stdin: read error\n"); - printf("/* ERROR: stdin */\n"); - } - } - - return err; -} diff --git a/contrib/tools/chkfmt b/contrib/tools/chkfmt deleted file mode 100755 index 9da6475fd..000000000 --- a/contrib/tools/chkfmt +++ /dev/null @@ -1,137 +0,0 @@ -#!/bin/sh -# -# Check the format of the source files in the current directory - checks for a -# line length of 80 characters max and no tab characters. -# -# Optionally arguments are files or directories to check. -# -# -v: output the long lines (makes fixing them easier) -# -e: spawn an editor for each file that needs a change ($EDITOR must be -# defined). When using -e the script MUST be run from an interactive -# command line. -verbose= -edit= -vers= -test "$1" = "-v" && { - shift - verbose=yes -} -test "$1" = "-e" && { - shift - if test -n "$EDITOR" - then - edit=yes - - # Copy the standard streams for the editor - exec 3>&0 4>&1 5>&2 - else - echo "chkfmt -e: EDITOR must be defined" >&2 - exit 1 - fi -} - -# Function to edit a single file - if the file isn't changed ask the user -# whether or not to continue. This stuff only works if the script is run from -# the command line (otherwise, don't specify -e or you will be sorry). -doed(){ - cp "$file" "$file".orig - "$EDITOR" "$file" 0>&3 1>&4 2>&5 3>&- 4>&- 5>&- || exit 1 - if cmp -s "$file".orig "$file" - then - rm "$file".orig - echo -n "$file: file not changed, type anything to continue: " >&5 - read ans 0>&3 - test -n "$ans" || return 1 - fi - return 0 -} - -# In beta versions the version string which appears in files can be a little -# long and cause spuriously overlong lines. To avoid this subtitute the version -# string with a 'standard' version a.b.cc before checking for long lines. -if test -r png.h -then - vers="`sed -n -e \ - 's/^#define PNG_LIBPNG_VER_STRING .\([0-9]\.[0-9]\.[0-9][0-9a-z]*\).$/\1/p' \ - png.h`" - echo "chkfmt: checking version $vers" -fi -if test -z "$vers" -then - echo "chkfmt: png.h not found, ignoring version number" >&2 -fi - -test -n "$1" || set -- . -find "$@" \( -type d \( -name '.git' -o -name '.libs' -o -name 'projects' \) \ - -prune \) -o \( -type f \ - ! -name '*.[oa]' ! -name '*.l[oa]' ! -name '*.png' ! -name '*.out' \ - ! -name '*.jpg' ! -name '*.patch' ! -name '*.obj' ! -name '*.exe' \ - ! -name '*.com' ! -name '*.tar.*' ! -name '*.zip' ! -name '*.ico' \ - ! -name '*.res' ! -name '*.rc' ! -name '*.mms' ! -name '*.rej' \ - ! -name '*.dsp' ! -name '*.orig' ! -name '*.dfn' ! -name '*.swp' \ - ! -name '~*' ! -name '*.3' \ - ! -name 'missing' ! -name 'mkinstalldirs' ! -name 'depcomp' \ - ! -name 'aclocal.m4' ! -name 'install-sh' ! -name 'Makefile.in' \ - ! -name 'ltmain.sh' ! -name 'config*' -print \) | { - st=0 - while read file - do - case "$file" in - *.mak|*[Mm]akefile.*|*[Mm]akefile) - # Makefiles require tabs, dependency lines can be this long. - check_tabs= - line_length=100;; - *.awk) - # Includes literal tabs - check_tabs= - # The following is arbitrary - line_length=132;; - *contrib/*/*.[ch]) - check_tabs=yes - line_length=96;; - *) - check_tabs=yes - line_length=80;; - esac - - # Note that vers can only contain 0-9, . and a-z - if test -n "$vers" - then - sed -e "s/$vers/a.b.cc/g" "$file" >"$file".$$ - else - cp "$file" "$file".$$ - fi - splt="`fold -$line_length "$file".$$ | diff -c "$file".$$ -`" - rm "$file".$$ - - if test -n "$splt" - then - echo "$file: lines too long" - st=1 - if test -n "$EDITOR" -a -n "$edit" - then - doed "$file" || exit 1 - elif test -n "$verbose" - then - echo "$splt" - fi - fi - if test -n "$check_tabs" - then - tab="`tr -c -d '\t' <"$file"`" - if test -n "$tab" - then - echo "$file: file contains tab characters" - st=1 - if test -n "$EDITOR" -a -n "$edit" - then - doed "$file" || exit 1 - elif test -n "$verbose" - then - echo "$splt" - fi - fi - fi - done - exit $st -} diff --git a/contrib/tools/cvtcolor.c b/contrib/tools/cvtcolor.c index e6793c7d5..b3776236b 100644 --- a/contrib/tools/cvtcolor.c +++ b/contrib/tools/cvtcolor.c @@ -1,9 +1,9 @@ /*- * convert.c * - * Last changed in libpng 1.6.0 [February 14, 2013] + * Last changed in libpng 1.6.0 [(PENDING RELEASE)] * - * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * COPYRIGHT: Written by John Cunningham Bowler, 2012. * To the extent possible under law, the author has waived all copyright and * related or neighboring rights to this work. This work is published from: * United States. diff --git a/contrib/tools/intgamma.sh b/contrib/tools/intgamma.sh index 41c5d6dd2..36a66d3be 100644 --- a/contrib/tools/intgamma.sh +++ b/contrib/tools/intgamma.sh @@ -2,9 +2,9 @@ # # intgamma.sh # -# Last changed in libpng 1.6.0 [February 14, 2013] +# Last changed in libpng 1.6.0 [(PENDING RELEASE)] # -# COPYRIGHT: Written by John Cunningham Bowler, 2013. +# COPYRIGHT: Written by John Cunningham Bowler, 2012. # To the extent possible under law, the author has waived all copyright and # related or neighboring rights to this work. This work is published from: # United States. diff --git a/contrib/tools/makesRGB.c b/contrib/tools/makesRGB.c index e66c9f157..0f7e7c7b4 100644 --- a/contrib/tools/makesRGB.c +++ b/contrib/tools/makesRGB.c @@ -1,8 +1,8 @@ /* makesRGB.c -- build sRGB-to-linear and linear-to-sRGB conversion tables * - * Last changed in libpng 1.6.0 [February 14, 2013] + * Last changed in libpng 1.6.0 [(PENDING RELEASE)] * - * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * COPYRIGHT: Written by John Cunningham Bowler, 2012. * To the extent possible under law, the author has waived all copyright and * related or neighboring rights to this work. This work is published from: * United States. diff --git a/contrib/tools/sRGB.h b/contrib/tools/sRGB.h index 22c8f7c0e..3b192bb39 100644 --- a/contrib/tools/sRGB.h +++ b/contrib/tools/sRGB.h @@ -1,9 +1,9 @@ /*- * sRGB.h * - * Last changed in libpng 1.6.0 [February 14, 2013] + * Last changed in libpng 1.6.0 [(PENDING RELEASE)] * - * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * COPYRIGHT: Written by John Cunningham Bowler, 2012. * To the extent possible under law, the author has waived all copyright and * related or neighboring rights to this work. This work is published from: * United States. diff --git a/contrib/visupng/PngFile.h b/contrib/visupng/PngFile.h index 474426c22..32181a4ea 100644 --- a/contrib/visupng/PngFile.h +++ b/contrib/visupng/PngFile.h @@ -17,7 +17,7 @@ void PngFileInitialize (HWND hwnd) ; BOOL PngFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) ; BOOL PngFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) ; -BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData, +BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData, int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor); BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData, int iWidth, int iHeight, png_color BkgColor); |