1b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* pngvalid.c - validate libpng by constructing then reading png files. 3b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 4b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Last changed in libpng 1.6.10 [March 6, 2014] 5b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Copyright (c) 2014 Glenn Randers-Pehrson 6b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Written by John Cunningham Bowler 7b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This code is released under the libpng license. 9b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * For conditions of distribution and use, see the disclaimer 10b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * and license in png.h 11b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 12b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * NOTES: 13b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This is a C program that is intended to be linked against libpng. It 14b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * generates bitmaps internally, stores them as PNG files (using the 15b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * sequential write code) then reads them back (using the sequential 16b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * read code) and validates that the result has the correct data. 17b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 18b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The program can be modified and extended to test the correctness of 19b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transformations performed by libpng. 20b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 21b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 22b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define _POSIX_SOURCE 1 23b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define _ISOC99_SOURCE 1 /* For floating point */ 24b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define _GNU_SOURCE 1 /* For the floating point exception extension */ 25b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 26b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#include <signal.h> 27b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#include <stdio.h> 28b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 29b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) 30b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# include <config.h> 31b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 32b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 33b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef HAVE_FEENABLEEXCEPT /* from config.h, if included */ 34b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# include <fenv.h> 35b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 36b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 37b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Define the following to use this test against your installed libpng, rather 38b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * than the one being built here: 39b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 40b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_FREESTANDING_TESTS 41b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# include <png.h> 42b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 43b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# include "../../png.h" 44b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 45b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 46b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_ZLIB_HEADER 47b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# include PNG_ZLIB_HEADER 48b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else 49b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# include <zlib.h> /* For crc32 */ 50b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif 51b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 52b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* 1.6.1 added support for the configure test harness, which uses 77 to indicate 53b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * a skipped test, in earlier versions we need to succeed on a skipped test, so: 54b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 55b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if PNG_LIBPNG_VER < 10601 56b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define SKIP 0 57b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else 58b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define SKIP 77 59b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif 60b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 61b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* pngvalid requires write support and one of the fixed or floating point APIs. 62b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 63b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if defined(PNG_WRITE_SUPPORTED) &&\ 64b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari (defined(PNG_FIXED_POINT_SUPPORTED) || defined(PNG_FLOATING_POINT_SUPPORTED)) 65b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 66b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if PNG_LIBPNG_VER < 10500 67b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This deliberately lacks the PNG_CONST. */ 68b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef png_byte *png_const_bytep; 69b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 70b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This is copied from 1.5.1 png.h: */ 71b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_INTERLACE_ADAM7_PASSES 7 72b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7) 73b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7) 74b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) 75b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) 76b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_PASS_ROWS(height, pass) (((height)+(((1<<PNG_PASS_ROW_SHIFT(pass))\ 77b50c217251b086440efcdb273c22f86a06c80cbaChris Craik -1)-PNG_PASS_START_ROW(pass)))>>PNG_PASS_ROW_SHIFT(pass)) 78b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_PASS_COLS(width, pass) (((width)+(((1<<PNG_PASS_COL_SHIFT(pass))\ 79b50c217251b086440efcdb273c22f86a06c80cbaChris Craik -1)-PNG_PASS_START_COL(pass)))>>PNG_PASS_COL_SHIFT(pass)) 80b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ 81b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (((yIn)<<PNG_PASS_ROW_SHIFT(pass))+PNG_PASS_START_ROW(pass)) 82b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_COL_FROM_PASS_COL(xIn, pass) \ 83b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (((xIn)<<PNG_PASS_COL_SHIFT(pass))+PNG_PASS_START_COL(pass)) 84b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_PASS_MASK(pass,off) ( \ 85b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((0x110145AFU>>(((7-(off))-(pass))<<2)) & 0xFU) | \ 86b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U)) 87b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ 88b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) 89b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ 90b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) 91b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 92b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* These are needed too for the default build: */ 93b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_WRITE_16BIT_SUPPORTED 94b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_READ_16BIT_SUPPORTED 95b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 96b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This comes from pnglibconf.h afer 1.5: */ 97b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_FP_1 100000 98b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PNG_GAMMA_THRESHOLD_FIXED\ 99b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1)) 100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if PNG_LIBPNG_VER < 10600 103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 1.6.0 constifies many APIs, the following exists to allow pngvalid to be 104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * compiled against earlier versions. 105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define png_const_structp png_structp 107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#include <float.h> /* For floating point constants */ 110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#include <stdlib.h> /* For malloc */ 111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#include <string.h> /* For memcpy, memset */ 112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#include <math.h> /* For floor */ 113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Unused formal parameter errors are removed using the following macro which is 115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * expected to have no bad effects on performance. 116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifndef UNUSED 118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if defined(__GNUC__) || defined(_MSC_VER) 119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define UNUSED(param) (void)param; 120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define UNUSED(param) 122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/***************************** EXCEPTION HANDLING *****************************/ 126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_FREESTANDING_TESTS 127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# include <cexcept.h> 128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# include "../visupng/cexcept.h" 130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef __cplusplus 133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define this not_the_cpp_this 134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define new not_the_cpp_new 135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define voidcast(type, value) static_cast<type>(value) 136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define voidcast(type, value) (value) 138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* __cplusplus */ 139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 140b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstruct png_store; 141b50c217251b086440efcdb273c22f86a06c80cbaChris Craikdefine_exception_type(struct png_store*); 142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following are macros to reduce typing everywhere where the well known 144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * name 'the_exception_context' must be defined. 145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define anon_context(ps) struct exception_context *the_exception_context = \ 147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik &(ps)->exception_context 148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define context(ps,fault) anon_context(ps); png_store *fault 149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/******************************* UTILITIES ************************************/ 151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Error handling is particularly problematic in production code - error 152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * handlers often themselves have bugs which lead to programs that detect 153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * minor errors crashing. The following functions deal with one very 154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * common class of errors in error handlers - attempting to format error or 155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * warning messages into buffers that are too small. 156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 157b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t safecat(char *buffer, size_t bufsize, size_t pos, 158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *cat) 159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (pos < bufsize && cat != NULL && *cat != 0) 161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[pos++] = *cat++; 162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pos >= bufsize) 164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = bufsize-1; 165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[pos] = 0; 167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pos; 168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 170b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t safecatn(char *buffer, size_t bufsize, size_t pos, int n) 171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char number[64]; 173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(number, "%d", n); 174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return safecat(buffer, bufsize, pos, number); 175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_TRANSFORMS_SUPPORTED 178b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t safecatd(char *buffer, size_t bufsize, size_t pos, double d, 179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int precision) 180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char number[64]; 182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(number, "%.*f", precision, d); 183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return safecat(buffer, bufsize, pos, number); 184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 187b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic PNG_CONST char invalid[] = "invalid"; 188b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic PNG_CONST char sep[] = ": "; 189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 190b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic PNG_CONST char *colour_types[8] = 191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "grayscale", invalid, "truecolour", "indexed-colour", 193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "grayscale with alpha", invalid, "truecolour with alpha", invalid 194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}; 195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Convert a double precision value to fixed point. */ 198b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_fixed_point 199b50c217251b086440efcdb273c22f86a06c80cbaChris Craikfix(double d) 200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d = floor(d * PNG_FP_1 + .5); 202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (png_fixed_point)d; 203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Generate random bytes. This uses a boring repeatable algorithm and it 207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is implemented here so that it gives the same set of numbers on every 208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * architecture. It's a linear congruential generator (Knuth or Sedgewick 209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and 210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Hill, "The Art of Electronics" (Pseudo-Random Bit Sequences and Noise 211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Generation.) 212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 213b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 214b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_random_bytes(png_uint_32* seed, void* pv, size_t size) 215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 u0 = seed[0], u1 = seed[1]; 217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_bytep bytes = voidcast(png_bytep, pv); 218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There are thirty three bits, the next bit in the sequence is bit-33 XOR 220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. 221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t i; 223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<size; ++i) 224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* First generate 8 new bits then shift them in at the end. */ 226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 u = ((u0 >> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; 227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik u1 <<= 8; 228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik u1 |= u0 >> 24; 229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik u0 <<= 8; 230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik u0 |= u; 231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *bytes++ = (png_byte)u; 232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik seed[0] = u0; 235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik seed[1] = u1; 236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 238b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 239b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_four_random_bytes(png_uint_32* seed, png_bytep bytes) 240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_random_bytes(seed, bytes, 4); 242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 245b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 246b50c217251b086440efcdb273c22f86a06c80cbaChris Craikrandomize(void *pv, size_t size) 247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static png_uint_32 random_seed[2] = {0x56789abc, 0xd}; 249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_random_bytes(random_seed, pv, size); 250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define RANDOMIZE(this) randomize(&(this), sizeof (this)) 253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 254b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic unsigned int 255b50c217251b086440efcdb273c22f86a06c80cbaChris Craikrandom_mod(unsigned int max) 256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int x; 258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik RANDOMIZE(x); 260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return x % max; /* 0 .. max-1 */ 262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED 265b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 266b50c217251b086440efcdb273c22f86a06c80cbaChris Craikrandom_choice(void) 267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned char x; 269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik RANDOMIZE(x); 271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return x & 1; 273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A numeric ID based on PNG file characteristics. The 'do_interlace' field 278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * simply records whether pngvalid did the interlace itself or whether it 279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * was done by libpng. Width and height must be less than 256. 'palette' is an 280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * index of the palette to use for formats with a palette (0 otherwise.) 281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define FILEID(col, depth, palette, interlace, width, height, do_interlace) \ 283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \ 284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (((do_interlace)!=0)<<15) + ((width)<<16) + ((height)<<24))) 285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define COL_FROM_ID(id) ((png_byte)((id)& 0x7U)) 287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU)) 288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PALETTE_FROM_ID(id) (((id) >> 8) & 0x1f) 289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3)) 290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1)) 291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define WIDTH_FROM_ID(id) (((id)>>16) & 0xff) 292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define HEIGHT_FROM_ID(id) (((id)>>24) & 0xff) 293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Utility to construct a standard name for a standard image. */ 295b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 296b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_name(char *buffer, size_t bufsize, size_t pos, png_byte colour_type, 297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int bit_depth, unsigned int npalette, int interlace_type, 298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 w, png_uint_32 h, int do_interlace) 299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, colour_types[colour_type]); 301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (npalette > 0) 302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "["); 304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(buffer, bufsize, pos, npalette); 305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "]"); 306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, " "); 308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(buffer, bufsize, pos, bit_depth); 309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, " bit"); 310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (interlace_type != PNG_INTERLACE_NONE) 312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, " interlaced"); 314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_interlace) 315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "(pngvalid)"); 316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "(libpng)"); 318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (w > 0 || h > 0) 321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, " "); 323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(buffer, bufsize, pos, w); 324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "x"); 325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(buffer, bufsize, pos, h); 326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pos; 329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 331b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 332b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id) 333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return standard_name(buffer, bufsize, pos, COL_FROM_ID(id), 335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik DEPTH_FROM_ID(id), PALETTE_FROM_ID(id), INTERLACE_FROM_ID(id), 336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik WIDTH_FROM_ID(id), HEIGHT_FROM_ID(id), DO_INTERLACE_FROM_ID(id)); 337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Convenience API and defines to list valid formats. Note that 16 bit read and 340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * write support is required to do 16 bit read tests (we must be able to make a 341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 16 bit image to test!) 342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_WRITE_16BIT_SUPPORTED 344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define WRITE_BDHI 4 345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_16BIT_SUPPORTED 346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define READ_BDHI 4 347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define DO_16BIT 348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define WRITE_BDHI 3 351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifndef DO_16BIT 353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define READ_BDHI 3 354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following defines the number of different palettes to generate for 357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * each log bit depth of a colour type 3 standard image. 358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PALETTE_COUNT(bit_depth) ((bit_depth) > 4 ? 1U : 16U) 360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 361b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 362b50c217251b086440efcdb273c22f86a06c80cbaChris Craiknext_format(png_bytep colour_type, png_bytep bit_depth, 363b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari unsigned int* palette_number, int no_low_depth_gray) 364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (*bit_depth == 0) 366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 367b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *colour_type = 0; 368b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (no_low_depth_gray) 369b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *bit_depth = 8; 370b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 371b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *bit_depth = 1; 372b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *palette_number = 0; 373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (*colour_type == 3) 377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Add multiple palettes for colour type 3. */ 379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (++*palette_number < PALETTE_COUNT(*bit_depth)) 380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *palette_number = 0; 383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *bit_depth = (png_byte)(*bit_depth << 1); 386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Palette images are restricted to 8 bit depth */ 388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (*bit_depth <= 8 389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef DO_16BIT 390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik || (*colour_type != 3 && *bit_depth <= 16) 391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ) 393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Move to the next color type, or return 0 at the end. */ 396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (*colour_type) 397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 0: 399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *colour_type = 2; 400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *bit_depth = 8; 401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 2: 404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *colour_type = 3; 405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *bit_depth = 1; 406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 3: 409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *colour_type = 4; 410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *bit_depth = 8; 411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 4: 414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *colour_type = 6; 415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *bit_depth = 8; 416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_TRANSFORMS_SUPPORTED 424b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic unsigned int 425b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksample(png_const_bytep row, png_byte colour_type, png_byte bit_depth, 426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 x, unsigned int sample_index) 427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 bit_index, result; 429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Find a sample index for the desired sample: */ 431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik x *= bit_depth; 432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_index = x; 433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((colour_type & 1) == 0) /* !palette */ 435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type & 2) 437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_index *= 3; 438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type & 4) 440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_index += x; /* Alpha channel */ 441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Multiple channels; select one: */ 443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type & (2+4)) 444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_index += sample_index * bit_depth; 445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Return the sample from the row as an integer. */ 448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row += bit_index >> 3; 449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik result = *row; 450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (bit_depth == 8) 452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return result; 453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (bit_depth > 8) 455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (result << 8) + *++row; 456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Less than 8 bits per sample. */ 458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_index &= 7; 459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (result >> (8-bit_index-bit_depth)) & ((1U<<bit_depth)-1); 460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ 462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Copy a single pixel, of a given size, from one buffer to another - 464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * while this is basically bit addressed there is an implicit assumption 465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that pixels 8 or more bits in size are byte aligned and that pixels 466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * do not otherwise cross byte boundaries. (This is, so far as I know, 467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * universally true in bitmap computer graphics. [JCB 20101212]) 468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * NOTE: The to and from buffers may be the same. 470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 471b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 472b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpixel_copy(png_bytep toBuffer, png_uint_32 toIndex, 473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize) 474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Assume we can multiply by 'size' without overflow because we are 476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * just working in a single buffer. 477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik toIndex *= pixelSize; 479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fromIndex *= pixelSize; 480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pixelSize < 8) /* Sub-byte */ 481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Mask to select the location of the copied pixel: */ 483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int destMask = ((1U<<pixelSize)-1) << (8-pixelSize-(toIndex&7)); 484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following read the entire pixels and clears the extra: */ 485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int destByte = toBuffer[toIndex >> 3] & ~destMask; 486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int sourceByte = fromBuffer[fromIndex >> 3]; 487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Don't rely on << or >> supporting '0' here, just in case: */ 489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fromIndex &= 7; 490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fromIndex > 0) sourceByte <<= fromIndex; 491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7; 492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik toBuffer[toIndex >> 3] = (png_byte)(destByte | (sourceByte & destMask)); 494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* One or more bytes */ 496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memmove(toBuffer+(toIndex>>3), fromBuffer+(fromIndex>>3), pixelSize>>3); 497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Copy a complete row of pixels, taking into account potential partial 501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bytes at the end. 502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 503b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 504b50c217251b086440efcdb273c22f86a06c80cbaChris Craikrow_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth) 505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memcpy(toBuffer, fromBuffer, bitWidth >> 3); 507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((bitWidth & 7) != 0) 509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int mask; 511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik toBuffer += bitWidth >> 3; 513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fromBuffer += bitWidth >> 3; 514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The remaining bits are in the top of the byte, the mask is the bits to 515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * retain. 516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mask = 0xff >> (bitWidth & 7); 518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *toBuffer = (png_byte)((*toBuffer & mask) | (*fromBuffer & ~mask)); 519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Compare pixels - they are assumed to start at the first byte in the 523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * given buffers. 524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 525b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 526b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpixel_cmp(png_const_bytep pa, png_const_bytep pb, png_uint_32 bit_width) 527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if PNG_LIBPNG_VER < 10506 529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (memcmp(pa, pb, bit_width>>3) == 0) 530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 p; 532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((bit_width & 7) == 0) return 0; 534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Ok, any differences? */ 536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik p = pa[bit_width >> 3]; 537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik p ^= pb[bit_width >> 3]; 538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (p == 0) return 0; 540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There are, but they may not be significant, remove the bits 542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * after the end (the low order bits in PNG.) 543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_width &= 7; 545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik p >>= 8-bit_width; 546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (p == 0) return 0; 548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* From libpng-1.5.6 the overwrite should be fixed, so compare the trailing 551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bits too: 552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (memcmp(pa, pb, (bit_width+7)>>3) == 0) 554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Return the index of the changed byte. */ 558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 where = 0; 560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (pa[where] == pb[where]) ++where; 562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1+where; 563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*************************** BASIC PNG FILE WRITING ***************************/ 568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A png_store takes data from the sequential writer or provides data 569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to the sequential reader. It can also store the result of a PNG 570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * write for later retrieval. 571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define STORE_BUFFER_SIZE 500 /* arbitrary */ 573b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct png_store_buffer 574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct png_store_buffer* prev; /* NOTE: stored in reverse order */ 576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte buffer[STORE_BUFFER_SIZE]; 577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} png_store_buffer; 578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define FILE_NAME_SIZE 64 580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 581b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct store_palette_entry /* record of a single palette entry */ 582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte red; 584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte green; 585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte blue; 586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte alpha; 587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} store_palette_entry, store_palette[256]; 588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 589b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct png_store_file 590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct png_store_file* next; /* as many as you like... */ 592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[FILE_NAME_SIZE]; 593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 id; /* must be correct (see FILEID) */ 594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t datacount; /* In this (the last) buffer */ 595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_buffer data; /* Last buffer in file */ 596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npalette; /* Number of entries in palette */ 597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette_entry* palette; /* May be NULL */ 598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} png_store_file; 599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following is a pool of memory allocated by a single libpng read or write 601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * operation. 602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 603b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct store_pool 604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct png_store *store; /* Back pointer */ 606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct store_memory *list; /* List of allocated memory */ 607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte mark[4]; /* Before and after data */ 608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Statistics for this run. */ 610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t max; /* Maximum single allocation */ 611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t current; /* Current allocation */ 612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t limit; /* Highest current allocation */ 613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t total; /* Total allocation */ 614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Overall statistics (retained across successive runs). */ 616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t max_max; 617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t max_limit; 618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t max_total; 619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} store_pool; 620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 621b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct png_store 622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For cexcept.h exception handling - simply store one of these; 624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the context is a self pointer but it may point to a different 625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_store (in fact it never does in this program.) 626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct exception_context 628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik exception_context; 629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int verbose :1; 631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int treat_warnings_as_errors :1; 632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int expect_error :1; 633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int expect_warning :1; 634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int saw_warning :1; 635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int speed :1; 636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int progressive :1; /* use progressive read */ 637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int validated :1; /* used as a temporary flag */ 638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int nerrors; 639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int nwarnings; 640b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int noptions; /* number of options below: */ 641b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari struct { 642b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari unsigned char option; /* option number, 0..30 */ 643b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari unsigned char setting; /* setting (unset,invalid,on,off) */ 644b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } options[16]; 645b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari char test[128]; /* Name of test */ 646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char error[256]; 647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Read fields */ 649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pread; /* Used to read a saved file */ 650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop piread; 651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_file* current; /* Set when reading */ 652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_buffer* next; /* Set when reading */ 653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t readpos; /* Position in *next */ 654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte* image; /* Buffer for reading interlaced images */ 655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t cb_image; /* Size of this buffer */ 656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t cb_row; /* Row size of the image(s) */ 657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 image_h; /* Number of rows in a single image */ 658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool read_memory_pool; 659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Write fields */ 661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_file* saved; 662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pwrite; /* Used when writing a new file */ 663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop piwrite; 664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t writepos; /* Position in .new */ 665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char wname[FILE_NAME_SIZE]; 666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_buffer new; /* The end of the new PNG file being written. */ 667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool write_memory_pool; 668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette_entry* palette; 669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npalette; 670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} png_store; 671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Initialization and cleanup */ 673b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 674b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_pool_mark(png_bytep mark) 675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static png_uint_32 store_seed[2] = { 0x12345678, 1}; 677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_four_random_bytes(store_seed, mark); 679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Use this for random 32 bit values; this function makes sure the result is 683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * non-zero. 684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 685b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 686b50c217251b086440efcdb273c22f86a06c80cbaChris Craikrandom_32(void) 687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for(;;) 690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte mark[4]; 692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 result; 693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_mark(mark); 695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik result = png_get_uint_32(mark); 696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (result != 0) 698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return result; 699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 703b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 704b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_pool_init(png_store *ps, store_pool *pool) 705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(pool, 0, sizeof *pool); 707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->store = ps; 709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->list = NULL; 710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->max = pool->current = pool->limit = pool->total = 0; 711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->max_max = pool->max_limit = pool->max_total = 0; 712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_mark(pool->mark); 713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 715b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 716b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_init(png_store* ps) 717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(ps, 0, sizeof *ps); 719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_exception_context(&ps->exception_context); 720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_init(ps, &ps->read_memory_pool); 721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_init(ps, &ps->write_memory_pool); 722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->verbose = 0; 723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->treat_warnings_as_errors = 0; 724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->expect_error = 0; 725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->expect_warning = 0; 726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->saw_warning = 0; 727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->speed = 0; 728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->progressive = 0; 729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->validated = 0; 730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->nerrors = ps->nwarnings = 0; 731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->pread = NULL; 732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->piread = NULL; 733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->saved = ps->current = NULL; 734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->next = NULL; 735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->readpos = 0; 736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->image = NULL; 737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->cb_image = 0; 738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->cb_row = 0; 739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->image_h = 0; 740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->pwrite = NULL; 741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->piwrite = NULL; 742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->writepos = 0; 743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->new.prev = NULL; 744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->palette = NULL; 745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->npalette = 0; 746b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ps->noptions = 0; 747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 749b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 750b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_freebuffer(png_store_buffer* psb) 751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (psb->prev) 753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_freebuffer(psb->prev); 755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik free(psb->prev); 756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik psb->prev = NULL; 757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 760b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 761b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_freenew(png_store *ps) 762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_freebuffer(&ps->new); 764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->writepos = 0; 765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->palette != NULL) 766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik free(ps->palette); 768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->palette = NULL; 769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->npalette = 0; 770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 773b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 774b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_storenew(png_store *ps) 775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_buffer *pb; 777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->writepos != STORE_BUFFER_SIZE) 779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pwrite, "invalid store call"); 780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pb = voidcast(png_store_buffer*, malloc(sizeof *pb)); 782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pb == NULL) 784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pwrite, "store new: OOM"); 785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *pb = ps->new; 787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->new.prev = pb; 788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->writepos = 0; 789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 791b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 792b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_freefile(png_store_file **ppf) 793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (*ppf != NULL) 795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_freefile(&(*ppf)->next); 797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_freebuffer(&(*ppf)->data); 799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (*ppf)->datacount = 0; 800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((*ppf)->palette != NULL) 801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik free((*ppf)->palette); 803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (*ppf)->palette = NULL; 804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (*ppf)->npalette = 0; 805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik free(*ppf); 807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *ppf = NULL; 808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Main interface to file storeage, after writing a new PNG file (see the API 812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * below) call store_storefile to store the result with the given name and id. 813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 814b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 815b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_storefile(png_store *ps, png_uint_32 id) 816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_file *pf = voidcast(png_store_file*, malloc(sizeof *pf)); 818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pf == NULL) 819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pwrite, "storefile: OOM"); 820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik safecat(pf->name, sizeof pf->name, 0, ps->wname); 821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pf->id = id; 822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pf->data = ps->new; 823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pf->datacount = ps->writepos; 824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->new.prev = NULL; 825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->writepos = 0; 826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pf->palette = ps->palette; 827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pf->npalette = ps->npalette; 828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->palette = 0; 829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->npalette = 0; 830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And save it. */ 832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pf->next = ps->saved; 833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->saved = pf; 834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Generate an error message (in the given buffer) */ 837b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 838b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_message(png_store *ps, png_const_structp pp, char *buffer, size_t bufsize, 839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos, PNG_CONST char *msg) 840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp != NULL && pp == ps->pread) 842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Reading a file */ 844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "read: "); 845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->current != NULL) 847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ps->current->name); 849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, sep); 850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (pp != NULL && pp == ps->pwrite) 854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Writing a file */ 856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "write: "); 857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ps->wname); 858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, sep); 859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Neither reading nor writing (or a memory error in struct delete) */ 864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "pngvalid: "); 865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->test[0] != 0) 868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ps->test); 870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, sep); 871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, msg); 873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pos; 874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Verbose output to the error stream: */ 877b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 878b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_verbose(png_store *ps, png_const_structp pp, png_const_charp prefix, 879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_charp message) 880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char buffer[512]; 882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (prefix) 884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fputs(prefix, stderr); 885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)store_message(ps, pp, buffer, sizeof buffer, 0, message); 887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fputs(buffer, stderr); 888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fputc('\n', stderr); 889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Log an error or warning - the relevant count is always incremented. */ 892b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 893b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_log(png_store* ps, png_const_structp pp, png_const_charp message, 894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int is_error) 895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The warning is copied to the error buffer if there are no errors and it is 897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the first warning. The error is copied to the error buffer if it is the 898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * first error (overwriting any prior warnings). 899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (is_error ? (ps->nerrors)++ == 0 : 901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (ps->nwarnings)++ == 0 && ps->nerrors == 0) 902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_message(ps, pp, ps->error, sizeof ps->error, 0, message); 903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->verbose) 905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_verbose(ps, pp, is_error ? "error: " : "warning: ", message); 906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Internal error function, called with a png_store but no libpng stuff. */ 910b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 911b50c217251b086440efcdb273c22f86a06c80cbaChris Craikinternal_error(png_store *ps, png_const_charp message) 912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, NULL, message, 1 /* error */); 914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And finally throw an exception. */ 916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct exception_context *the_exception_context = &ps->exception_context; 918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Functions to use as PNG callbacks. */ 924b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 925b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_error(png_structp ppIn, png_const_charp message) /* PNG_NORETURN */ 926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); 929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!ps->expect_error) 931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, pp, message, 1 /* error */); 932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And finally throw an exception. */ 934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct exception_context *the_exception_context = &ps->exception_context; 936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 940b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 941b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_warning(png_structp ppIn, png_const_charp message) 942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store *ps = voidcast(png_store*, png_get_error_ptr(pp)); 945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!ps->expect_warning) 947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, pp, message, 0 /* warning */); 948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->saw_warning = 1; 950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* These somewhat odd functions are used when reading an image to ensure that 953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the buffer is big enough, the png_structp is for errors. 954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Return a single row from the correct image. */ 956b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_bytep 957b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_image_row(PNG_CONST png_store* ps, png_const_structp pp, int nImage, 958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y) 959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t coffset = (nImage * ps->image_h + y) * (ps->cb_row + 5) + 2; 961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->image == NULL) 963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "no allocated image"); 964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (coffset + ps->cb_row + 3 > ps->cb_image) 966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "image too small"); 967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return ps->image + coffset; 969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 971b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 972b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_image_free(png_store *ps, png_const_structp pp) 973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->image != NULL) 975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_bytep image = ps->image; 977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (image[-1] != 0xed || image[ps->cb_image] != 0xfe) 979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp != NULL) 981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "png_store image overwrite (1)"); 982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, NULL, "png_store image overwrite (2)", 1); 984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->image = NULL; 987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->cb_image = 0; 988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik --image; 989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik free(image); 990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 993b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 994b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_ensure_image(png_store *ps, png_const_structp pp, int nImages, 995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t cbRow, png_uint_32 cRows) 996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t cb = nImages * cRows * (cbRow + 5); 998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->cb_image < cb) 1000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_bytep image; 1002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_free(ps, pp); 1004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The buffer is deliberately mis-aligned. */ 1006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image = voidcast(png_bytep, malloc(cb+2)); 1007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (image == NULL) 1008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Called from the startup - ignore the error for the moment. */ 1010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp == NULL) 1011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 1012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "OOM allocating image buffer"); 1014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* These magic tags are used to detect overwrites above. */ 1017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++image; 1018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image[-1] = 0xed; 1019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image[cb] = 0xfe; 1020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->image = image; 1022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->cb_image = cb; 1023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* We have an adequate sized image; lay out the rows. There are 2 bytes at 1026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the start and three at the end of each (this ensures that the row 1027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * alignment starts out odd - 2+1 and changes for larger images on each row.) 1028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->cb_row = cbRow; 1030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->image_h = cRows; 1031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For error checking, the whole buffer is set to 10110010 (0xb2 - 178). 1033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This deliberately doesn't match the bits in the size test image which are 1034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * outside the image; these are set to 0xff (all 1). To make the row 1035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * comparison work in the 'size' test case the size rows are pre-initialized 1036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to the same value prior to calling 'standard_row'. 1037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(ps->image, 178, cb); 1039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Then put in the marks. */ 1041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (--nImages >= 0) 1042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 1044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<cRows; ++y) 1046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_bytep row = store_image_row(ps, pp, nImages, y); 1048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The markers: */ 1050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row[-2] = 190; 1051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row[-1] = 239; 1052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row[cbRow] = 222; 1053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row[cbRow+1] = 173; 1054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row[cbRow+2] = 17; 1055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 1060b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1061b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage) 1062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_bytep image = ps->image; 1064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (image[-1] != 0xed || image[ps->cb_image] != 0xfe) 1066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "image overwrite"); 1067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 1068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t cbRow = ps->cb_row; 1070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 rows = ps->image_h; 1071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image += iImage * (cbRow+5) * ps->image_h; 1073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image += 2; /* skip image first row markers */ 1075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (rows-- > 0) 1077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (image[-2] != 190 || image[-1] != 239) 1079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "row start overwritten"); 1080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (image[cbRow] != 222 || image[cbRow+1] != 173 || 1082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image[cbRow+2] != 17) 1083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "row end overwritten"); 1084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image += cbRow+5; 1086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 1090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1091b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 1092b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_write(png_structp ppIn, png_bytep pb, png_size_t st) 1093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 1095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); 1096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pwrite != pp) 1098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "store state damaged"); 1099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (st > 0) 1101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t cb; 1103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->writepos >= STORE_BUFFER_SIZE) 1105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_storenew(ps); 1106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = st; 1108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cb > STORE_BUFFER_SIZE - ps->writepos) 1110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = STORE_BUFFER_SIZE - ps->writepos; 1111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memcpy(ps->new.buffer + ps->writepos, pb, cb); 1113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pb += cb; 1114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik st -= cb; 1115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->writepos += cb; 1116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1119b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 1120b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_flush(png_structp ppIn) 1121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(ppIn) /*DOES NOTHING*/ 1123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 1126b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 1127b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_read_buffer_size(png_store *ps) 1128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Return the bytes available for read in the current buffer. */ 1130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->next != &ps->current->data) 1131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return STORE_BUFFER_SIZE; 1132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return ps->current->datacount; 1134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_TRANSFORMS_SUPPORTED 1137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Return total bytes available for read. */ 1138b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 1139b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_read_buffer_avail(png_store *ps) 1140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->current != NULL && ps->next != NULL) 1142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_buffer *next = &ps->current->data; 1144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t cbAvail = ps->current->datacount; 1145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (next != ps->next && next != NULL) 1147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik next = next->prev; 1149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cbAvail += STORE_BUFFER_SIZE; 1150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (next != ps->next) 1153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pread, "buffer read error"); 1154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cbAvail > ps->readpos) 1156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return cbAvail - ps->readpos; 1157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 1160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 1162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1163b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 1164b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_read_buffer_next(png_store *ps) 1165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_buffer *pbOld = ps->next; 1167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_buffer *pbNew = &ps->current->data; 1168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pbOld != pbNew) 1169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (pbNew != NULL && pbNew->prev != pbOld) 1171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pbNew = pbNew->prev; 1172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pbNew != NULL) 1174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->next = pbNew; 1176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->readpos = 0; 1177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 1178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pread, "buffer lost"); 1181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; /* EOF or error */ 1184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Need separate implementation and callback to allow use of the same code 1187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * during progressive read, where the io_ptr is set internally by libpng. 1188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1189b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1190b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_read_imp(png_store *ps, png_bytep pb, png_size_t st) 1191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->current == NULL || ps->next == NULL) 1193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pread, "store state damaged"); 1194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (st > 0) 1196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t cbAvail = store_read_buffer_size(ps) - ps->readpos; 1198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cbAvail > 0) 1200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cbAvail > st) cbAvail = st; 1202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memcpy(pb, ps->next->buffer + ps->readpos, cbAvail); 1203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik st -= cbAvail; 1204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pb += cbAvail; 1205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->readpos += cbAvail; 1206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (!store_read_buffer_next(ps)) 1209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pread, "read beyond end of file"); 1210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1213b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 1214b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_read(png_structp ppIn, png_bytep pb, png_size_t st) 1215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 1217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store *ps = voidcast(png_store*, png_get_io_ptr(pp)); 1218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps == NULL || ps->pread != pp) 1220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "bad store read call"); 1221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_imp(ps, pb, st); 1223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1225b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1226b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_progressive_read(png_store *ps, png_structp pp, png_infop pi) 1227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Notice that a call to store_read will cause this function to fail because 1229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * readpos will be set. 1230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pread != pp || ps->current == NULL || ps->next == NULL) 1232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "store state damaged (progressive)"); 1233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik do 1235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->readpos != 0) 1237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "store_read called during progressive read"); 1238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_process_data(pp, pi, ps->next->buffer, store_read_buffer_size(ps)); 1240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (store_read_buffer_next(ps)); 1242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 1244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The caller must fill this in: */ 1246b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic store_palette_entry * 1247b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_write_palette(png_store *ps, int npalette) 1248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pwrite == NULL) 1250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, NULL, "attempt to write palette without write stream", 1); 1251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->palette != NULL) 1253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pwrite, "multiple store_write_palette calls"); 1254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This function can only return NULL if called with '0'! */ 1256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (npalette > 0) 1257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->palette = voidcast(store_palette_entry*, malloc(npalette * 1259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sizeof *ps->palette)); 1260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->palette == NULL) 1262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pwrite, "store new palette: OOM"); 1263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->npalette = npalette; 1265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return ps->palette; 1268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 1271b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic store_palette_entry * 1272b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_current_palette(png_store *ps, int *npalette) 1273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is an internal error (the call has been made outside a read 1275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * operation.) 1276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->current == NULL) 1278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, ps->pread, "no current stream for palette", 1); 1279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The result may be null if there is no palette. */ 1281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *npalette = ps->current->npalette; 1282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return ps->current->palette; 1283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 1285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/***************************** MEMORY MANAGEMENT*** ***************************/ 1287b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_USER_MEM_SUPPORTED 1288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A store_memory is simply the header for an allocated block of memory. The 1289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * pointer returned to libpng is just after the end of the header block, the 1290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * allocated memory is followed by a second copy of the 'mark'. 1291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1292b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct store_memory 1293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool *pool; /* Originating pool */ 1295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct store_memory *next; /* Singly linked list */ 1296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t size; /* Size of memory allocated */ 1297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte mark[4]; /* ID marker */ 1298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} store_memory; 1299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Handle a fatal error in memory allocation. This calls png_error if the 1301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng struct is non-NULL, else it outputs a message and returns. This means 1302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that a memory problem while libpng is running will abort (png_error) the 1303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * handling of particular file while one in cleanup (after the destroy of the 1304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * struct has returned) will simply keep going and free (or attempt to free) 1305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * all the memory. 1306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1307b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1308b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_pool_error(png_store *ps, png_const_structp pp, PNG_CONST char *msg) 1309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp != NULL) 1311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 1312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Else we have to do it ourselves. png_error eventually calls store_log, 1314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * above. store_log accepts a NULL png_structp - it just changes what gets 1315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * output by store_message. 1316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, pp, msg, 1 /* error */); 1318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1320b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1321b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_memory_free(png_const_structp pp, store_pool *pool, store_memory *memory) 1322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Note that pp may be NULL (see store_pool_delete below), the caller has 1324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * found 'memory' in pool->list *and* unlinked this entry, so this is a valid 1325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * pointer (for sure), but the contents may have been trashed. 1326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (memory->pool != pool) 1328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_error(pool->store, pp, "memory corrupted (pool)"); 1329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (memcmp(memory->mark, pool->mark, sizeof memory->mark) != 0) 1331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_error(pool->store, pp, "memory corrupted (start)"); 1332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* It should be safe to read the size field now. */ 1334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 1335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_alloc_size_t cb = memory->size; 1337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cb > pool->max) 1339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_error(pool->store, pp, "memory corrupted (size)"); 1340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (memcmp((png_bytep)(memory+1)+cb, pool->mark, sizeof pool->mark) 1342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik != 0) 1343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_error(pool->store, pp, "memory corrupted (end)"); 1344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Finally give the library a chance to find problems too: */ 1346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 1347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->current -= cb; 1349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik free(memory); 1350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1354b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1355b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_pool_delete(png_store *ps, store_pool *pool) 1356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pool->list != NULL) 1358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "%s: %s %s: memory lost (list follows):\n", ps->test, 1360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool == &ps->read_memory_pool ? "read" : "write", 1361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool == &ps->read_memory_pool ? (ps->current != NULL ? 1362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->current->name : "unknown file") : ps->wname); 1363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++ps->nerrors; 1364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik do 1366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_memory *next = pool->list; 1368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->list = next->next; 1369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik next->next = NULL; 1370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "\t%lu bytes @ %p\n", 1372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)next->size, (PNG_CONST void*)(next+1)); 1373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The NULL means this will always return, even if the memory is 1374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * corrupted. 1375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_memory_free(NULL, pool, next); 1377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (pool->list != NULL); 1379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And reset the other fields too for the next time. */ 1382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pool->max > pool->max_max) pool->max_max = pool->max; 1383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->max = 0; 1384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pool->current != 0) /* unexpected internal error */ 1385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "%s: %s %s: memory counter mismatch (internal error)\n", 1386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->test, pool == &ps->read_memory_pool ? "read" : "write", 1387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool == &ps->read_memory_pool ? (ps->current != NULL ? 1388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->current->name : "unknown file") : ps->wname); 1389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->current = 0; 1390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pool->limit > pool->max_limit) 1392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->max_limit = pool->limit; 1393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->limit = 0; 1395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pool->total > pool->max_total) 1397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->max_total = pool->total; 1398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->total = 0; 1400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Get a new mark too. */ 1402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_mark(pool->mark); 1403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The memory callbacks: */ 1406b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic png_voidp PNGCBAPI 1407b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_malloc(png_structp ppIn, png_alloc_size_t cb) 1408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 1410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp)); 1411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_memory *new = voidcast(store_memory*, malloc(cb + (sizeof *new) + 1412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (sizeof pool->mark))); 1413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (new != NULL) 1415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cb > pool->max) 1417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->max = cb; 1418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->current += cb; 1420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pool->current > pool->limit) 1422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->limit = pool->current; 1423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->total += cb; 1425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik new->size = cb; 1427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memcpy(new->mark, pool->mark, sizeof new->mark); 1428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memcpy((png_byte*)(new+1) + cb, pool->mark, sizeof pool->mark); 1429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik new->pool = pool; 1430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik new->next = pool->list; 1431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pool->list = new; 1432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++new; 1433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 1436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* NOTE: the PNG user malloc function cannot use the png_ptr it is passed 1438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * other than to retrieve the allocation pointer! libpng calls the 1439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * store_malloc callback in two basic cases: 1440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 1441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 1) From png_malloc; png_malloc will do a png_error itself if NULL is 1442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * returned. 1443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2) From png_struct or png_info structure creation; png_malloc is 1444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to return so cleanup can be performed. 1445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 1446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * To handle this store_malloc can log a message, but can't do anything 1447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * else. 1448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(pool->store, pp, "out of memory", 1 /* is_error */); 1450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return new; 1453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1455b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 1456b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_free(png_structp ppIn, png_voidp memory) 1457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 1459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp)); 1460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_memory *this = voidcast(store_memory*, memory), **test; 1461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Because libpng calls store_free with a dummy png_struct when deleting 1463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_struct or png_info via png_destroy_struct_2 it is necessary to check 1464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the passed in png_structp to ensure it is valid, and not pass it to 1465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_error if it is not. 1466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp != pool->store->pread && pp != pool->store->pwrite) 1468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp = NULL; 1469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* First check that this 'memory' really is valid memory - it must be in the 1471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * pool list. If it is, use the shared memory_free function to free it. 1472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik --this; 1474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (test = &pool->list; *test != this; test = &(*test)->next) 1475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (*test == NULL) 1477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_pool_error(pool->store, pp, "bad pointer to free"); 1479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 1480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Unlink this entry, *test == this. */ 1484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *test = this->next; 1485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = NULL; 1486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_memory_free(pp, pool, this); 1487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1488b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* PNG_USER_MEM_SUPPORTED */ 1489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Setup functions. */ 1491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Cleanup when aborting a write or after storing the new file. */ 1492b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1493b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_write_reset(png_store *ps) 1494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pwrite != NULL) 1496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik anon_context(ps); 1498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 1500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_destroy_write_struct(&ps->pwrite, &ps->piwrite); 1501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch_anonymous 1503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* memory corruption: continue. */ 1505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->pwrite = NULL; 1508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->piwrite = NULL; 1509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And make sure that all the memory has been freed - this will output 1512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * spurious errors in the case of memory corruption above, but this is safe. 1513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1514b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_USER_MEM_SUPPORTED 1515b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari store_pool_delete(ps, &ps->write_memory_pool); 1516b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 1517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_freenew(ps); 1519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following is the main write function, it returns a png_struct and, 1522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * optionally, a png_info suitable for writiing a new PNG file. Use 1523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * store_storefile above to record this file after it has been written. The 1524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * returned libpng structures as destroyed by store_write_reset above. 1525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1526b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_structp 1527b50c217251b086440efcdb273c22f86a06c80cbaChris Craikset_store_for_write(png_store *ps, png_infopp ppi, 1528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char * volatile name) 1529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik anon_context(ps); 1531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 1533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pwrite != NULL) 1535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pwrite, "write store already in use"); 1536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(ps); 1538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik safecat(ps->wname, sizeof ps->wname, 0, name); 1539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1540b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Don't do the slow memory checks if doing a speed test, also if user 1541b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * memory is not supported we can't do it anyway. 1542b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 1543b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_USER_MEM_SUPPORTED 1544b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (!ps->speed) 1545b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ps->pwrite = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, 1546b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ps, store_error, store_warning, &ps->write_memory_pool, 1547b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari store_malloc, store_free); 1548b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1549b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 1550b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 1551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->pwrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, 1552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps, store_error, store_warning); 1553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_write_fn(ps->pwrite, ps, store_write, store_flush); 1555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1556b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_SET_OPTION_SUPPORTED 1557b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 1558b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int opt; 1559b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari for (opt=0; opt<ps->noptions; ++opt) 1560b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (png_set_option(ps->pwrite, ps->options[opt].option, 1561b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ps->options[opt].setting) == PNG_OPTION_INVALID) 1562b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_error(ps->pwrite, "png option invalid"); 1563b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 1564b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 1565b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ppi != NULL) 1567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *ppi = ps->piwrite = png_create_info_struct(ps->pwrite); 1568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch_anonymous 1571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return NULL; 1572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return ps->pwrite; 1574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Cleanup when finished reading (either due to error or in the success case). 1577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This routine exists even when there is no read support to make the code 1578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * tidier (avoid a mass of ifdefs) and so easier to maintain. 1579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1580b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1581b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_read_reset(png_store *ps) 1582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_SUPPORTED 1584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pread != NULL) 1585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik anon_context(ps); 1587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 1589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_destroy_read_struct(&ps->pread, &ps->piread, NULL); 1590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch_anonymous 1592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* error already output: continue */ 1594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->pread = NULL; 1597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->piread = NULL; 1598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 1600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1601b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_USER_MEM_SUPPORTED 1602b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Always do this to be safe. */ 1603b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari store_pool_delete(ps, &ps->read_memory_pool); 1604b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 1605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->current = NULL; 1607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->next = NULL; 1608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->readpos = 0; 1609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->validated = 0; 1610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 1613b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1614b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_read_set(png_store *ps, png_uint_32 id) 1615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store_file *pf = ps->saved; 1617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (pf != NULL) 1619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pf->id == id) 1621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->current = pf; 1623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->next = NULL; 1624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_buffer_next(ps); 1625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 1626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pf = pf->next; 1629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1631b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 1632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos; 1633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[FILE_NAME_SIZE+64]; 1634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = standard_name_from_id(msg, sizeof msg, 0, id); 1636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, ": file not found"); 1637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pread, msg); 1638b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 1639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The main interface for reading a saved file - pass the id number of the file 1642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to retrieve. Ids must be unique or the earlier file will be hidden. The API 1643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * returns a png_struct and, optionally, a png_info. Both of these will be 1644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * destroyed by store_read_reset above. 1645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1646b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_structp 1647b50c217251b086440efcdb273c22f86a06c80cbaChris Craikset_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id, 1648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *name) 1649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set the name for png_error */ 1651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik safecat(ps->test, sizeof ps->test, 0, name); 1652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pread != NULL) 1654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(ps->pread, "read store already in use"); 1655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_reset(ps); 1657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Both the create APIs can return NULL if used in their default mode 1659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (because there is no other way of handling an error because the jmp_buf 1660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * by default is stored in png_struct and that has not been allocated!) 1661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * However, given that store_error works correctly in these circumstances 1662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * we don't ever expect NULL in this program. 1663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1664b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_USER_MEM_SUPPORTED 1665b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (!ps->speed) 1666b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ps->pread = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, ps, 1667b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari store_error, store_warning, &ps->read_memory_pool, store_malloc, 1668b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari store_free); 1669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1670b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 1671b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 1672b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ps->pread = png_create_read_struct(PNG_LIBPNG_VER_STRING, ps, store_error, 1673b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari store_warning); 1674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->pread == NULL) 1676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct exception_context *the_exception_context = &ps->exception_context; 1678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, NULL, "png_create_read_struct returned NULL (unexpected)", 1680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1 /*error*/); 1681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 1683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1685b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_SET_OPTION_SUPPORTED 1686b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 1687b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int opt; 1688b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari for (opt=0; opt<ps->noptions; ++opt) 1689b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (png_set_option(ps->pread, ps->options[opt].option, 1690b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ps->options[opt].setting) == PNG_OPTION_INVALID) 1691b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_error(ps->pread, "png option invalid"); 1692b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 1693b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 1694b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_set(ps, id); 1696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ppi != NULL) 1698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *ppi = ps->piread = png_create_info_struct(ps->pread); 1699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return ps->pread; 1701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 1703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The overall cleanup of a store simply calls the above then removes all the 1705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * saved files. This does not delete the store itself. 1706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1707b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1708b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstore_delete(png_store *ps) 1709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(ps); 1711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_reset(ps); 1712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_freefile(&ps->saved); 1713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_free(ps, NULL); 1714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*********************** PNG FILE MODIFICATION ON READ ************************/ 1717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Files may be modified on read. The following structure contains a complete 1718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_store together with extra members to handle modification and a special 1719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * read callback for libpng. To use this the 'modifications' field must be set 1720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to a list of png_modification structures that actually perform the 1721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * modification, otherwise a png_modifier is functionally equivalent to a 1722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_store. There is a special read function, set_modifier_for_read, which 1723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * replaces set_store_for_read. 1724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1725b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef enum modifier_state 1726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_start, /* Initial value */ 1728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_signature, /* Have a signature */ 1729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_IHDR /* Have an IHDR */ 1730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} modifier_state; 1731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1732b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct CIE_color 1733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* A single CIE tristimulus value, representing the unique response of a 1735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * standard observer to a variety of light spectra. The observer recognizes 1736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * all spectra that produce this response as the same color, therefore this 1737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is effectively a description of a color. 1738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double X, Y, Z; 1740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} CIE_color; 1741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1742b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct color_encoding 1743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* A description of an (R,G,B) encoding of color (as defined above); this 1745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * includes the actual colors of the (R,G,B) triples (1,0,0), (0,1,0) and 1746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (0,0,1) plus an encoding value that is used to encode the linear 1747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * components R, G and B to give the actual values R^gamma, G^gamma and 1748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * B^gamma that are stored. 1749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double gamma; /* Encoding (file) gamma of space */ 1751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CIE_color red, green, blue; /* End points */ 1752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} color_encoding; 1753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 1755b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double 1756b50c217251b086440efcdb273c22f86a06c80cbaChris Craikchromaticity_x(CIE_color c) 1757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return c.X / (c.X + c.Y + c.Z); 1759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1761b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double 1762b50c217251b086440efcdb273c22f86a06c80cbaChris Craikchromaticity_y(CIE_color c) 1763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return c.Y / (c.X + c.Y + c.Z); 1765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1767b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic CIE_color 1768b50c217251b086440efcdb273c22f86a06c80cbaChris Craikwhite_point(PNG_CONST color_encoding *encoding) 1769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CIE_color white; 1771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik white.X = encoding->red.X + encoding->green.X + encoding->blue.X; 1773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik white.Y = encoding->red.Y + encoding->green.Y + encoding->blue.Y; 1774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik white.Z = encoding->red.Z + encoding->green.Z + encoding->blue.Z; 1775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return white; 1777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED 1780b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1781b50c217251b086440efcdb273c22f86a06c80cbaChris Craiknormalize_color_encoding(color_encoding *encoding) 1782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double whiteY = encoding->red.Y + encoding->green.Y + 1784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->blue.Y; 1785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (whiteY != 1) 1787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->red.X /= whiteY; 1789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->red.Y /= whiteY; 1790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->red.Z /= whiteY; 1791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->green.X /= whiteY; 1792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->green.Y /= whiteY; 1793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->green.Z /= whiteY; 1794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->blue.X /= whiteY; 1795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->blue.Y /= whiteY; 1796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoding->blue.Z /= whiteY; 1797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 1800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1801b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 1802b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksafecat_color_encoding(char *buffer, size_t bufsize, size_t pos, 1803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST color_encoding *e, double encoding_gamma) 1804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (e != 0) 1806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoding_gamma != 0) 1808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "("); 1809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "R("); 1810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->red.X, 4); 1811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ","); 1812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->red.Y, 4); 1813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ","); 1814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->red.Z, 4); 1815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "),G("); 1816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->green.X, 4); 1817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ","); 1818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->green.Y, 4); 1819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ","); 1820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->green.Z, 4); 1821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "),B("); 1822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->blue.X, 4); 1823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ","); 1824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->blue.Y, 4); 1825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ","); 1826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, e->blue.Z, 4); 1827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ")"); 1828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoding_gamma != 0) 1829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, ")"); 1830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoding_gamma != 0) 1833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "^"); 1835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, bufsize, pos, encoding_gamma, 5); 1836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 1837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pos; 1839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 1841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1842b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct png_modifier 1843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store this; /* I am a png_store */ 1845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct png_modification *modifications; /* Changes to make */ 1846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_state state; /* My state */ 1848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Information from IHDR: */ 1850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth; /* From IHDR */ 1851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type; /* From IHDR */ 1852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* While handling PLTE, IDAT and IEND these chunks may be pended to allow 1854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * other chunks to be inserted. 1855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 pending_len; 1857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 pending_chunk; 1858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Test values */ 1860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double *gammas; 1861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int ngammas; 1862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int ngamma_tests; /* Number of gamma tests to run*/ 1863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double current_gamma; /* 0 if not set */ 1864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST color_encoding *encodings; 1865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int nencodings; 1866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST color_encoding *current_encoding; /* If an encoding has been set */ 1867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int encoding_counter; /* For iteration */ 1868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int encoding_ignored; /* Something overwrote it */ 1869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Control variables used to iterate through possible encodings, the 1871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * following must be set to 0 and tested by the function that uses the 1872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_modifier because the modifier only sets it to 1 (true.) 1873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int repeat :1; /* Repeat this transform test. */ 1875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_uses_encoding :1; 1876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Lowest sbit to test (libpng fails for sbit < 8) */ 1878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte sbitlow; 1879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Error control - these are the limits on errors accepted by the gamma tests 1881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * below. 1882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxout8; /* Maximum output value error */ 1884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxabs8; /* Absolute sample error 0..1 */ 1885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxcalc8; /* Absolute sample error 0..1 */ 1886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxpc8; /* Percentage sample error 0..100% */ 1887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxout16; /* Maximum output value error */ 1888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxabs16; /* Absolute sample error 0..1 */ 1889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxcalc16;/* Absolute sample error 0..1 */ 1890b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double maxcalcG; /* Absolute sample error 0..1 */ 1891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxpc16; /* Percentage sample error 0..100% */ 1892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is set by transforms that need to allow a higher limit, it is an 1894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * internal check on pngvalid to ensure that the calculated error limits are 1895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * not ridiculous; without this it is too easy to make a mistake in pngvalid 1896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that allows any value through. 1897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double limit; /* limit on error values, normally 4E-3 */ 1899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Log limits - values above this are logged, but not necessarily 1901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * warned. 1902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double log8; /* Absolute error in 8 bits to log */ 1904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double log16; /* Absolute error in 16 bits to log */ 1905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Logged 8 and 16 bit errors ('output' values): */ 1907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double error_gray_2; 1908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double error_gray_4; 1909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double error_gray_8; 1910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double error_gray_16; 1911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double error_color_8; 1912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double error_color_16; 1913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double error_indexed; 1914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Flags: */ 1916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Whether to call png_read_update_info, not png_read_start_image, and how 1917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * many times to call it. 1918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int use_update_info; 1920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Whether or not to interlace. */ 1922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int interlace_type :9; /* int, but must store '1' */ 1923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Run the standard tests? */ 1925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_standard :1; 1926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Run the odd-sized image and interlace read/write tests? */ 1928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_size :1; 1929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1930b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Run tests on reading with a combination of transforms, */ 1931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_transform :1; 1932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1933b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* When to use the use_input_precision option, this controls the gamma 1934b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * validation code checks. If set any value that is within the transformed 1935b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * range input-.5 to input+.5 will be accepted, otherwise the value must be 1936b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * within the normal limits. It should not be necessary to set this; the 1937b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * result should always be exact within the permitted error limits. 1938b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 1939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int use_input_precision :1; 1940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int use_input_precision_sbit :1; 1941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int use_input_precision_16to8 :1; 1942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If set assume that the calculation bit depth is set by the input 1944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * precision, not the output precision. 1945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int calculations_use_input_precision :1; 1947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1948b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* If set assume that the calculations are done in 16 bits even if the sample 1949b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * depth is 8 bits. 1950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int assume_16_bit_calculations :1; 1952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Which gamma tests to run: */ 1954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_gamma_threshold :1; 1955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_gamma_transform :1; /* main tests */ 1956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_gamma_sbit :1; 1957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_gamma_scale16 :1; 1958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_gamma_background :1; 1959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_gamma_alpha_mode :1; 1960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_gamma_expand16 :1; 1961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test_exhaustive :1; 1962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int log :1; /* Log max error */ 1964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Buffer information, the buffer size limits the size of the chunks that can 1966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * be modified - they must fit (including header and CRC) into the buffer! 1967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 1968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t flush; /* Count of bytes to flush */ 1969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t buffer_count; /* Bytes in buffer */ 1970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t buffer_position; /* Position in buffer */ 1971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte buffer[1024]; 1972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} png_modifier; 1973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This returns true if the test should be stopped now because it has already 1975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * failed and it is running silently. 1976b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 1977b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int fail(png_modifier *pm) 1978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return !pm->log && !pm->this.verbose && (pm->this.nerrors > 0 || 1980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (pm->this.treat_warnings_as_errors && pm->this.nwarnings > 0)); 1981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 1982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1983b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 1984b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_init(png_modifier *pm) 1985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 1986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(pm, 0, sizeof *pm); 1987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_init(&pm->this); 1988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->modifications = NULL; 1989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->state = modifier_start; 1990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->sbitlow = 1U; 1991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->ngammas = 0; 1992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->ngamma_tests = 0; 1993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->gammas = 0; 1994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_gamma = 0; 1995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encodings = 0; 1996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->nencodings = 0; 1997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_encoding = 0; 1998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_counter = 0; 1999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_ignored = 0; 2000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->repeat = 0; 2001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_uses_encoding = 0; 2002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0; 2003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0; 2004b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->maxcalcG = 0; 2005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->limit = 4E-3; 2006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->log8 = pm->log16 = 0; /* Means 'off' */ 2007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0; 2008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->error_gray_16 = pm->error_color_8 = pm->error_color_16 = 0; 2009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->error_indexed = 0; 2010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info = 0; 2011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->interlace_type = PNG_INTERLACE_NONE; 2012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_standard = 0; 2013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_size = 0; 2014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_transform = 0; 2015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision = 0; 2016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision_sbit = 0; 2017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision_16to8 = 0; 2018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->calculations_use_input_precision = 0; 2019b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->assume_16_bit_calculations = 0; 2020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_threshold = 0; 2021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_transform = 0; 2022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_sbit = 0; 2023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_scale16 = 0; 2024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_background = 0; 2025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_alpha_mode = 0; 2026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_expand16 = 0; 2027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_exhaustive = 0; 2028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->log = 0; 2029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Rely on the memset for all the other fields - there are no pointers */ 2031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_TRANSFORMS_SUPPORTED 2034b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 2035b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* This controls use of checks that explicitly know how libpng digitizes the 2036b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * samples in calculations; setting this circumvents simple error limit checking 2037b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * in the rgb_to_gray check, replacing it with an exact copy of the libpng 1.5 2038b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * algorithm. 2039b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 2040b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define DIGITIZE PNG_LIBPNG_VER < 10700 2041b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 2042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* If pm->calculations_use_input_precision is set then operations will happen 2043b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * with the precision of the input, not the precision of the output depth. 2044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * If pm->assume_16_bit_calculations is set then even 8 bit calculations use 16 2046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bit precision. This only affects those of the following limits that pertain 2047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to a calculation - not a digitization operation - unless the following API is 2048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * called directly. 2049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED 2051b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if DIGITIZE 2052b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic double digitize(double value, int depth, int do_round) 2053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 'value' is in the range 0 to 1, the result is the same value rounded to a 2055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * multiple of the digitization factor - 8 or 16 bits depending on both the 2056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * sample depth and the 'assume' setting. Digitization is normally by 2057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * rounding and 'do_round' should be 1, if it is 0 the digitized value will 2058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * be truncated. 2059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2060b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari PNG_CONST unsigned int digitization_factor = (1U << depth) -1; 2061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Limiting the range is done as a convenience to the caller - it's easier to 2063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * do it once here than every time at the call site. 2064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (value <= 0) 2066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik value = 0; 2067b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 2068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (value >= 1) 2069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik value = 1; 2070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik value *= digitization_factor; 2072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_round) value += .5; 2073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return floor(value)/digitization_factor; 2074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 2076b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* RGB_TO_GRAY */ 2077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2078b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_GAMMA_SUPPORTED 2079b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double abserr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) 2080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Absolute error permitted in linear values - affected by the bit depth of 2082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the calculations. 2083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2084b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (pm->assume_16_bit_calculations || 2085b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari (pm->calculations_use_input_precision ? in_depth : out_depth) == 16) 2086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxabs16; 2087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxabs8; 2089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2091b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double calcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) 2092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Error in the linear composition arithmetic - only relevant when 2094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * composition actually happens (0 < alpha < 1). 2095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2096b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16) 2097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxcalc16; 2098b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else if (pm->assume_16_bit_calculations) 2099b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return pm->maxcalcG; 2100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxcalc8; 2102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2104b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double pcerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) 2105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Percentage error permitted in the linear values. Note that the specified 2107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value is a percentage but this routine returns a simple number. 2108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2109b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (pm->assume_16_bit_calculations || 2110b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari (pm->calculations_use_input_precision ? in_depth : out_depth) == 16) 2111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxpc16 * .01; 2112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxpc8 * .01; 2114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Output error - the error in the encoded value. This is determined by the 2117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * digitization of the output so can be +/-0.5 in the actual output value. In 2118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the expand_16 case with the current code in libpng the expand happens after 2119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * all the calculations are done in 8 bit arithmetic, so even though the output 2120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * depth is 16 the output error is determined by the 8 bit calculation. 2121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This limit is not determined by the bit depth of internal calculations. 2123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The specified parameter does *not* include the base .5 digitization error but 2125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * it is added here. 2126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2127b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double outerr(PNG_CONST png_modifier *pm, int in_depth, int out_depth) 2128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There is a serious error in the 2 and 4 bit grayscale transform because 2130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the gamma table value (8 bits) is simply shifted, not rounded, so the 2131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * error in 4 bit grayscale gamma is up to the value below. This is a hack 2132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to allow pngvalid to succeed: 2133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * TODO: fix this in libpng 2135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (out_depth == 2) 2137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return .73182-.5; 2138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (out_depth == 4) 2140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return .90644-.5; 2141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2142b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16) 2143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxout16; 2144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is the case where the value was calculated at 8-bit precision then 2146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * scaled to 16 bits. 2147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (out_depth == 16) 2149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxout8 * 257; 2150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->maxout8; 2153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This does the same thing as the above however it returns the value to log, 2156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * rather than raising a warning. This is useful for debugging to track down 2157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * exactly what set of parameters cause high error values. 2158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2159b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double outlog(PNG_CONST png_modifier *pm, int in_depth, int out_depth) 2160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The command line parameters are either 8 bit (0..255) or 16 bit (0..65535) 2162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * and so must be adjusted for low bit depth grayscale: 2163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (out_depth <= 8) 2165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->log8 == 0) /* switched off */ 2167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 256; 2168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (out_depth < 8) 2170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->log8 / 255 * ((1<<out_depth)-1); 2171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->log8; 2173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2175b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if ((pm->calculations_use_input_precision ? in_depth : out_depth) == 16) 2176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->log16 == 0) 2178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 65536; 2179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->log16; 2181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is the case where the value was calculated at 8-bit precision then 2184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * scaled to 16 bits. 2185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->log8 == 0) 2187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 65536; 2188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->log8 * 257; 2190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This complements the above by providing the appropriate quantization for the 2193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * final value. Normally this would just be quantization to an integral value, 2194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * but in the 8 bit calculation case it's actually quantization to a multiple of 2195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 257! 2196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2197b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int output_quantization_factor(PNG_CONST png_modifier *pm, int in_depth, 2198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int out_depth) 2199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2200b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (out_depth == 16 && in_depth != 16 && 2201b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->calculations_use_input_precision) 2202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 257; 2203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 2205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_GAMMA_SUPPORTED */ 2207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* One modification structure must be provided for each chunk to be modified (in 2209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * fact more than one can be provided if multiple separate changes are desired 2210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * for a single chunk.) Modifications include adding a new chunk when a 2211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * suitable chunk does not exist. 2212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The caller of modify_fn will reset the CRC of the chunk and record 'modified' 2214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * or 'added' as appropriate if the modify_fn returns 1 (true). If the 2215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * modify_fn is NULL the chunk is simply removed. 2216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2217b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct png_modification 2218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct png_modification *next; 2220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 chunk; 2221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If the following is NULL all matching chunks will be removed: */ 2223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int (*modify_fn)(struct png_modifier *pm, 2224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct png_modification *me, int add); 2225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If the following is set to PLTE, IDAT or IEND and the chunk has not been 2227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * found and modified (and there is a modify_fn) the modify_fn will be called 2228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to add the chunk before the relevant chunk. 2229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 add; 2231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int modified :1; /* Chunk was modified */ 2232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int added :1; /* Chunk was added */ 2233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int removed :1; /* Chunk was removed */ 2234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} png_modification; 2235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2236b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2237b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodification_reset(png_modification *pmm) 2238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pmm != NULL) 2240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pmm->modified = 0; 2242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pmm->added = 0; 2243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pmm->removed = 0; 2244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modification_reset(pmm->next); 2245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2248b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2249b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodification_init(png_modification *pmm) 2250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(pmm, 0, sizeof *pmm); 2252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pmm->next = NULL; 2253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pmm->chunk = 0; 2254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pmm->modify_fn = NULL; 2255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pmm->add = 0; 2256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modification_reset(pmm); 2257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED 2260b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2261b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_current_encoding(PNG_CONST png_modifier *pm, color_encoding *ce) 2262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->current_encoding != 0) 2264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *ce = *pm->current_encoding; 2265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(ce, 0, sizeof *ce); 2268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ce->gamma = pm->current_gamma; 2270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 2272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2273b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 2274b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksafecat_current_encoding(char *buffer, size_t bufsize, size_t pos, 2275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_modifier *pm) 2276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat_color_encoding(buffer, bufsize, pos, pm->current_encoding, 2278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_gamma); 2279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->encoding_ignored) 2281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, bufsize, pos, "[overridden]"); 2282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pos; 2284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Iterate through the usefully testable color encodings. An encoding is one 2287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of: 2288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 1) Nothing (no color space, no gamma). 2290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2) Just a gamma value from the gamma array (including 1.0) 2291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 3) A color space from the encodings array with the corresponding gamma. 2292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 4) The same, but with gamma 1.0 (only really useful with 16 bit calculations) 2293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The iterator selects these in turn, the randomizer selects one at random, 2295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * which is used depends on the setting of the 'test_exhaustive' flag. Notice 2296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that this function changes the colour space encoding so it must only be 2297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * called on completion of the previous test. This is what 'modifier_reset' 2298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * does, below. 2299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * After the function has been called the 'repeat' flag will still be set; the 2301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * caller of modifier_reset must reset it at the start of each run of the test! 2302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2303b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic unsigned int 2304b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_total_encodings(PNG_CONST png_modifier *pm) 2305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1 + /* (1) nothing */ 2307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->ngammas + /* (2) gamma values to test */ 2308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->nencodings + /* (3) total number of encodings */ 2309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following test only works after the first time through the 2310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_modifier code because 'bit_depth' is set when the IHDR is read. 2311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * modifier_reset, below, preserves the setting until after it has called 2312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the iterate function (also below.) 2313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * For this reason do not rely on this function outside a call to 2315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * modifier_reset. 2316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((pm->bit_depth == 16 || pm->assume_16_bit_calculations) ? 2318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->nencodings : 0); /* (4) encodings with gamma == 1.0 */ 2319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2321b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2322b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_encoding_iterate(png_modifier *pm) 2323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!pm->repeat && /* Else something needs the current encoding again. */ 2325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_uses_encoding) /* Some transform is encoding dependent */ 2326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_exhaustive) 2328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (++pm->encoding_counter >= modifier_total_encodings(pm)) 2330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_counter = 0; /* This will stop the repeat */ 2331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Not exhaustive - choose an encoding at random; generate a number in 2336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the range 1..(max-1), so the result is always non-zero: 2337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->encoding_counter == 0) 2339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_counter = random_mod(modifier_total_encodings(pm)-1)+1; 2340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_counter = 0; 2342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->encoding_counter > 0) 2345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->repeat = 1; 2346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (!pm->repeat) 2349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_counter = 0; 2350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2352b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2353b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_reset(png_modifier *pm) 2354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_reset(&pm->this); 2356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->limit = 4E-3; 2357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->pending_len = pm->pending_chunk = 0; 2358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->flush = pm->buffer_count = pm->buffer_position = 0; 2359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->modifications = NULL; 2360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->state = modifier_start; 2361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_encoding_iterate(pm); 2362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following must be set in the next run. In particular 2363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * test_uses_encodings must be set in the _ini function of each transform 2364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that looks at the encodings. (Not the 'add' function!) 2365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_uses_encoding = 0; 2367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_gamma = 0; 2368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_encoding = 0; 2369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_ignored = 0; 2370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* These only become value after IHDR is read: */ 2371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->bit_depth = pm->colour_type = 0; 2372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following must be called before anything else to get the encoding set up 2375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * on the modifier. In particular it must be called before the transform init 2376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * functions are called. 2377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2378b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2379b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_set_encoding(png_modifier *pm) 2380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set the encoding to the one specified by the current encoding counter, 2382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * first clear out all the settings - this corresponds to an encoding_counter 2383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of 0. 2384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_gamma = 0; 2386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_encoding = 0; 2387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_ignored = 0; /* not ignored yet - happens in _ini functions. */ 2388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now, if required, set the gamma and encoding fields. */ 2390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->encoding_counter > 0) 2391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The gammas[] array is an array of screen gammas, not encoding gammas, 2393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * so we need the inverse: 2394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->encoding_counter <= pm->ngammas) 2396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_gamma = 1/pm->gammas[pm->encoding_counter-1]; 2397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int i = pm->encoding_counter - pm->ngammas; 2401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (i >= pm->nencodings) 2403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik i %= pm->nencodings; 2405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_gamma = 1; /* Linear, only in the 16 bit case */ 2406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_gamma = pm->encodings[i].gamma; 2410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_encoding = pm->encodings + i; 2412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Enquiry functions to find out what is set. Notice that there is an implicit 2417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * assumption below that the first encoding in the list is the one for sRGB. 2418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2419b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 2420b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_color_encoding_is_sRGB(PNG_CONST png_modifier *pm) 2421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->current_encoding != 0 && pm->current_encoding == pm->encodings && 2423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->current_encoding->gamma == pm->current_gamma; 2424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2426b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 2427b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_color_encoding_is_set(PNG_CONST png_modifier *pm) 2428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return pm->current_gamma != 0; 2430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Convenience macros. */ 2433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d)) 2434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_IHDR CHUNK(73,72,68,82) 2435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_PLTE CHUNK(80,76,84,69) 2436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_IDAT CHUNK(73,68,65,84) 2437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_IEND CHUNK(73,69,78,68) 2438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_cHRM CHUNK(99,72,82,77) 2439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_gAMA CHUNK(103,65,77,65) 2440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_sBIT CHUNK(115,66,73,84) 2441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define CHUNK_sRGB CHUNK(115,82,71,66) 2442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The guts of modification are performed during a read. */ 2444b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2445b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_crc(png_bytep buffer) 2446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Recalculate the chunk CRC - a complete chunk must be in 2448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the buffer, at the start. 2449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik uInt datalen = png_get_uint_32(buffer); 2451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik uLong crc = crc32(0, buffer+4, datalen+4); 2452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The cast to png_uint_32 is safe because a crc32 is always a 32 bit value. 2453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(buffer+datalen+8, (png_uint_32)crc); 2455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2457b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2458b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_setbuffer(png_modifier *pm) 2459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_crc(pm->buffer); 2461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = png_get_uint_32(pm->buffer)+12; 2462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position = 0; 2463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Separate the callback into the actual implementation (which is passed the 2466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_modifier explicitly) and the callback, which gets the modifier from the 2467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_struct. 2468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2469b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2470b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st) 2471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (st > 0) 2473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t cb; 2475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 len, chunk; 2476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modification *mod; 2477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->buffer_position >= pm->buffer_count) switch (pm->state) 2479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static png_byte sign[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; 2481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case modifier_start: 2482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_imp(&pm->this, pm->buffer, 8); /* size of signature. */ 2483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = 8; 2484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position = 0; 2485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (memcmp(pm->buffer, sign, 8) != 0) 2487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pm->this.pread, "invalid PNG file signature"); 2488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->state = modifier_signature; 2489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case modifier_signature: 2492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_imp(&pm->this, pm->buffer, 13+12); /* size of IHDR */ 2493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = 13+12; 2494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position = 0; 2495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_uint_32(pm->buffer) != 13 || 2497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_get_uint_32(pm->buffer+4) != CHUNK_IHDR) 2498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pm->this.pread, "invalid IHDR"); 2499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the list of modifiers for modifications to the IHDR. */ 2501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod = pm->modifications; 2502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (mod != NULL) 2503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (mod->chunk == CHUNK_IHDR && mod->modify_fn && 2505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (*mod->modify_fn)(pm, mod, 0)) 2506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod->modified = 1; 2508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_setbuffer(pm); 2509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Ignore removal or add if IHDR! */ 2512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod = mod->next; 2513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Cache information from the IHDR (the modified one.) */ 2516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->bit_depth = pm->buffer[8+8]; 2517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->colour_type = pm->buffer[8+8+1]; 2518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->state = modifier_IHDR; 2520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->flush = 0; 2521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case modifier_IHDR: 2524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 2525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Read a new chunk and process it until we see PLTE, IDAT or 2526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * IEND. 'flush' indicates that there is still some data to 2527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * output from the preceding chunk. 2528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((cb = pm->flush) > 0) 2530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cb > st) cb = st; 2532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->flush -= cb; 2533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_imp(&pm->this, pb, cb); 2534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pb += cb; 2535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik st -= cb; 2536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (st == 0) return; 2537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* No more bytes to flush, read a header, or handle a pending 2540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * chunk. 2541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->pending_chunk != 0) 2543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer, pm->pending_len); 2545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+4, pm->pending_chunk); 2546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->pending_len = 0; 2547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->pending_chunk = 0; 2548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_imp(&pm->this, pm->buffer, 8); 2551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = 8; 2553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position = 0; 2554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for something to modify or a terminator chunk. */ 2556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik len = png_get_uint_32(pm->buffer); 2557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik chunk = png_get_uint_32(pm->buffer+4); 2558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Terminators first, they may have to be delayed for added 2560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * chunks 2561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (chunk == CHUNK_PLTE || chunk == CHUNK_IDAT || 2563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik chunk == CHUNK_IEND) 2564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod = pm->modifications; 2566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (mod != NULL) 2568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((mod->add == chunk || 2570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (mod->add == CHUNK_PLTE && chunk == CHUNK_IDAT)) && 2571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod->modify_fn != NULL && !mod->modified && !mod->added) 2572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Regardless of what the modify function does do not run 2574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this again. 2575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod->added = 1; 2577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((*mod->modify_fn)(pm, mod, 1 /*add*/)) 2579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Reset the CRC on a new chunk */ 2581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->buffer_count > 0) 2582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_setbuffer(pm); 2583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position = 0; 2587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod->removed = 1; 2588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The buffer has been filled with something (we assume) 2591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * so output this. Pend the current chunk. 2592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->pending_len = len; 2594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->pending_chunk = chunk; 2595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; /* out of while */ 2596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod = mod->next; 2600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Don't do any further processing if the buffer was modified - 2603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * otherwise the code will end up modifying a chunk that was 2604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * just added. 2605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (mod != NULL) 2607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; /* out of switch */ 2608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If we get to here then this chunk may need to be modified. To 2611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * do this it must be less than 1024 bytes in total size, otherwise 2612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * it just gets flushed. 2613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (len+12 <= sizeof pm->buffer) 2615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_imp(&pm->this, pm->buffer+pm->buffer_count, 2617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik len+12-pm->buffer_count); 2618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = len+12; 2619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for a modification, else leave it be. */ 2621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod = pm->modifications; 2622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (mod != NULL) 2623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (mod->chunk == chunk) 2625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (mod->modify_fn == NULL) 2627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Remove this chunk */ 2629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = pm->buffer_position = 0; 2630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod->removed = 1; 2631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; /* Terminate the while loop */ 2632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if ((*mod->modify_fn)(pm, mod, 0)) 2635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod->modified = 1; 2637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The chunk may have been removed: */ 2638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->buffer_count == 0) 2639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position = 0; 2641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_setbuffer(pm); 2644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mod = mod->next; 2648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->flush = len+12 - pm->buffer_count; /* data + crc */ 2653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Take the data from the buffer (if there is any). */ 2655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Here to read from the modifier buffer (not directly from 2659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the store, as in the flush case above.) 2660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = pm->buffer_count - pm->buffer_position; 2662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cb > st) 2664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = st; 2665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memcpy(pb, pm->buffer + pm->buffer_position, cb); 2667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik st -= cb; 2668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pb += cb; 2669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position += cb; 2670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The callback: */ 2674b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 2675b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_read(png_structp ppIn, png_bytep pb, png_size_t st) 2676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 2678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modifier *pm = voidcast(png_modifier*, png_get_io_ptr(pp)); 2679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm == NULL || pm->this.pread != pp) 2681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "bad modifier_read call"); 2682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_read_imp(pm, pb, st); 2684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Like store_progressive_read but the data is getting changed as we go so we 2687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * need a local buffer. 2688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2689b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2690b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmodifier_progressive_read(png_modifier *pm, png_structp pp, png_infop pi) 2691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->this.pread != pp || pm->this.current == NULL || 2693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->this.next == NULL) 2694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "store state damaged (progressive)"); 2695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is another Horowitz and Hill random noise generator. In this case 2697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the aim is to stress the progressive reader with truly horrible variable 2698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * buffer sizes in the range 1..500, so a sequence of 9 bit random numbers 2699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is generated. We could probably just count from 1 to 32767 and get as 2700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * good a result. 2701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (;;) 2703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static png_uint_32 noise = 1; 2705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_size_t cb, cbAvail; 2706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte buffer[512]; 2707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Generate 15 more bits of stuff: */ 2709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik noise = (noise << 9) | ((noise ^ (noise >> (9-5))) & 0x1ff); 2710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = noise & 0x1ff; 2711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check that this number of bytes are available (in the current buffer.) 2713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (This doesn't quite work - the modifier might delete a chunk; unlikely 2714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * but possible, it doesn't happen at present because the modifier only 2715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * adds chunks to standard images.) 2716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cbAvail = store_read_buffer_avail(&pm->this); 2718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->buffer_count > pm->buffer_position) 2719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cbAvail += pm->buffer_count - pm->buffer_position; 2720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cb > cbAvail) 2722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for EOF: */ 2724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (cbAvail == 0) 2725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = cbAvail; 2728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_read_imp(pm, buffer, cb); 2731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_process_data(pp, pi, buffer, cb); 2732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the invariants at the end (if this fails it's a problem in this 2735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * file!) 2736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->buffer_count > pm->buffer_position || 2738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->this.next != &pm->this.current->data || 2739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->this.readpos < pm->this.current->datacount) 2740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "progressive read implementation error"); 2741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Set up a modifier. */ 2744b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_structp 2745b50c217251b086440efcdb273c22f86a06c80cbaChris Craikset_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id, 2746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *name) 2747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Do this first so that the modifier fields are cleared even if an error 2749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * happens allocating the png_struct. No allocation is done here so no 2750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * cleanup is required. 2751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->state = modifier_start; 2753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->bit_depth = 0; 2754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->colour_type = 255; 2755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->pending_len = 0; 2757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->pending_chunk = 0; 2758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->flush = 0; 2759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = 0; 2760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_position = 0; 2761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return set_store_for_read(&pm->this, ppi, id, name); 2763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/******************************** MODIFICATIONS *******************************/ 2767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Standard modifications to add chunks. These do not require the _SUPPORTED 2768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * macros because the chunks can be there regardless of whether this specific 2769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng supports them. 2770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 2771b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct gama_modification 2772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modification this; 2774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_fixed_point gamma; 2775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} gama_modification; 2776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2777b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 2778b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgama_modify(png_modifier *pm, png_modification *me, int add) 2779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(add) 2781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This simply dumps the given gamma value into the buffer. */ 2782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer, 4); 2783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+4, CHUNK_gAMA); 2784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+8, ((gama_modification*)me)->gamma); 2785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 2786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2788b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2789b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgama_modification_init(gama_modification *me, png_modifier *pm, double gammad) 2790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double g; 2792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modification_init(&me->this); 2794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.chunk = CHUNK_gAMA; 2795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.modify_fn = gama_modify; 2796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.add = CHUNK_PLTE; 2797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik g = fix(gammad); 2798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->gamma = (png_fixed_point)g; 2799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.next = pm->modifications; 2800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->modifications = &me->this; 2801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2803b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct chrm_modification 2804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modification this; 2806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST color_encoding *encoding; 2807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_fixed_point wx, wy, rx, ry, gx, gy, bx, by; 2808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} chrm_modification; 2809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2810b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 2811b50c217251b086440efcdb273c22f86a06c80cbaChris Craikchrm_modify(png_modifier *pm, png_modification *me, int add) 2812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(add) 2814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* As with gAMA this just adds the required cHRM chunk to the buffer. */ 2815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer , 32); 2816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+ 4, CHUNK_cHRM); 2817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+ 8, ((chrm_modification*)me)->wx); 2818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+12, ((chrm_modification*)me)->wy); 2819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+16, ((chrm_modification*)me)->rx); 2820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+20, ((chrm_modification*)me)->ry); 2821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+24, ((chrm_modification*)me)->gx); 2822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+28, ((chrm_modification*)me)->gy); 2823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+32, ((chrm_modification*)me)->bx); 2824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+36, ((chrm_modification*)me)->by); 2825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 2826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2828b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2829b50c217251b086440efcdb273c22f86a06c80cbaChris Craikchrm_modification_init(chrm_modification *me, png_modifier *pm, 2830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST color_encoding *encoding) 2831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CIE_color white = white_point(encoding); 2833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Original end points: */ 2835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->encoding = encoding; 2836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Chromaticities (in fixed point): */ 2838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->wx = fix(chromaticity_x(white)); 2839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->wy = fix(chromaticity_y(white)); 2840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->rx = fix(chromaticity_x(encoding->red)); 2842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->ry = fix(chromaticity_y(encoding->red)); 2843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->gx = fix(chromaticity_x(encoding->green)); 2844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->gy = fix(chromaticity_y(encoding->green)); 2845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->bx = fix(chromaticity_x(encoding->blue)); 2846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->by = fix(chromaticity_y(encoding->blue)); 2847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modification_init(&me->this); 2849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.chunk = CHUNK_cHRM; 2850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.modify_fn = chrm_modify; 2851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.add = CHUNK_PLTE; 2852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.next = pm->modifications; 2853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->modifications = &me->this; 2854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2856b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct srgb_modification 2857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modification this; 2859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte intent; 2860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} srgb_modification; 2861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2862b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 2863b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksrgb_modify(png_modifier *pm, png_modification *me, int add) 2864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(add) 2866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* As above, ignore add and just make a new chunk */ 2867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer, 1); 2868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+4, CHUNK_sRGB); 2869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer[8] = ((srgb_modification*)me)->intent; 2870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 2871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2873b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2874b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksrgb_modification_init(srgb_modification *me, png_modifier *pm, png_byte intent) 2875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modification_init(&me->this); 2877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.chunk = CHUNK_sBIT; 2878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (intent <= 3) /* if valid, else *delete* sRGB chunks */ 2880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.modify_fn = srgb_modify; 2882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.add = CHUNK_PLTE; 2883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->intent = intent; 2884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.modify_fn = 0; 2889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.add = 0; 2890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->intent = 0; 2891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.next = pm->modifications; 2894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->modifications = &me->this; 2895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_GAMMA_SUPPORTED 2898b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct sbit_modification 2899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modification this; 2901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte sbit; 2902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} sbit_modification; 2903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2904b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 2905b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksbit_modify(png_modifier *pm, png_modification *me, int add) 2906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte sbit = ((sbit_modification*)me)->sbit; 2908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->bit_depth > sbit) 2909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int cb = 0; 2911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (pm->colour_type) 2912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 0: 2914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = 1; 2915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 2: 2918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 3: 2919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = 3; 2920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 4: 2923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = 2; 2924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 6: 2927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cb = 4; 2928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 2929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 2931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pm->this.pread, 2932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "unexpected colour type in sBIT modification"); 2933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer, cb); 2936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_save_uint_32(pm->buffer+4, CHUNK_sBIT); 2937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (cb > 0) 2939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (pm->buffer+8)[--cb] = sbit; 2940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 2942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (!add) 2944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 2945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Remove the sBIT chunk */ 2946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->buffer_count = pm->buffer_position = 0; 2947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 2948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 2949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 2950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; /* do nothing */ 2951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2953b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 2954b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksbit_modification_init(sbit_modification *me, png_modifier *pm, png_byte sbit) 2955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 2956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modification_init(&me->this); 2957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.chunk = CHUNK_sBIT; 2958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.modify_fn = sbit_modify; 2959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.add = CHUNK_PLTE; 2960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->sbit = sbit; 2961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik me->this.next = pm->modifications; 2962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->modifications = &me->this; 2963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 2964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_GAMMA_SUPPORTED */ 2965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ 2966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 2967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/***************************** STANDARD PNG FILES *****************************/ 2968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Standard files - write and save standard files. */ 2969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* There are two basic forms of standard images. Those which attempt to have 2970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * all the possible pixel values (not possible for 16bpp images, but a range of 2971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * values are produced) and those which have a range of image sizes. The former 2972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * are used for testing transforms, in particular gamma correction and bit 2973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * reduction and increase. The latter are reserved for testing the behavior of 2974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng with respect to 'odd' image sizes - particularly small images where 2975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * rows become 1 byte and interlace passes disappear. 2976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The first, most useful, set are the 'transform' images, the second set of 2978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * small images are the 'size' images. 2979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The transform files are constructed with rows which fit into a 1024 byte row 2981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * buffer. This makes allocation easier below. Further regardless of the file 2982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * format every row has 128 pixels (giving 1024 bytes for 64bpp formats). 2983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Files are stored with no gAMA or sBIT chunks, with a PLTE only when needed 2985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * and with an ID derived from the colour type, bit depth and interlace type 2986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * as above (FILEID). The width (128) and height (variable) are not stored in 2987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the FILEID - instead the fields are set to 0, indicating a transform file. 2988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The size files ar constructed with rows a maximum of 128 bytes wide, allowing 2990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * a maximum width of 16 pixels (for the 64bpp case.) They also have a maximum 2991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * height of 16 rows. The width and height are stored in the FILEID and, being 2992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * non-zero, indicate a size file. 2993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 2994b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Because the PNG filter code is typically the largest CPU consumer within 2995b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * libpng itself there is a tendency to attempt to optimize it. This results in 2996b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * special case code which needs to be validated. To cause this to happen the 2997b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 'size' images are made to use each possible filter, in so far as this is 2998b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * possible for smaller images. 2999b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 3000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * For palette image (colour type 3) multiple transform images are stored with 3001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the same bit depth to allow testing of more colour combinations - 3002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * particularly important for testing the gamma code because libpng uses a 3003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * different code path for palette images. For size images a single palette is 3004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * used. 3005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Make a 'standard' palette. Because there are only 256 entries in a palette 3008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (maximum) this actually makes a random palette in the hope that enough tests 3009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * will catch enough errors. (Note that the same palette isn't produced every 3010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * time for the same test - it depends on what previous tests have been run - 3011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * but a given set of arguments to pngvalid will always produce the same palette 3012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * at the same test! This is why pseudo-random number generators are useful for 3013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * testing.) 3014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 3015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The store must be open for write when this is called, otherwise an internal 3016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * error will occur. This routine contains its own magic number seed, so the 3017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * palettes generated don't change if there are intervening errors (changing the 3018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * calls to the store_mark seed.) 3019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3020b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic store_palette_entry * 3021b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_standard_palette(png_store* ps, int npalette, int do_tRNS) 3022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static png_uint_32 palette_seed[2] = { 0x87654321, 9 }; 3024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i = 0; 3026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte values[256][4]; 3027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Always put in black and white plus the six primary and secondary colors. 3029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; i<8; ++i) 3031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i][1] = (png_byte)((i&1) ? 255U : 0U); 3033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i][2] = (png_byte)((i&2) ? 255U : 0U); 3034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i][3] = (png_byte)((i&4) ? 255U : 0U); 3035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Then add 62 grays (one quarter of the remaining 256 slots). */ 3038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int j = 0; 3040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte random_bytes[4]; 3041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte need[256]; 3042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik need[0] = 0; /*got black*/ 3044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(need+1, 1, (sizeof need)-2); /*need these*/ 3045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik need[255] = 0; /*but not white*/ 3046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<70) 3048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte b; 3050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (j==0) 3052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_four_random_bytes(palette_seed, random_bytes); 3054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik j = 4; 3055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik b = random_bytes[--j]; 3058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (need[b]) 3059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i][1] = b; 3061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i][2] = b; 3062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i++][3] = b; 3063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Finally add 192 colors at random - don't worry about matches to things we 3068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * already have, chance is less than 1/65536. Don't worry about grays, 3069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * chance is the same, so we get a duplicate or extra gray less than 1 time 3070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in 170. 3071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; i<256; ++i) 3073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_four_random_bytes(palette_seed, values[i]); 3074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Fill in the alpha values in the first byte. Just use all possible values 3076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (0..255) in an apparently random order: 3077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette_entry *palette; 3080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte selector[4]; 3081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_four_random_bytes(palette_seed, selector); 3083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_tRNS) 3085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<256; ++i) 3086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i][0] = (png_byte)(i ^ selector[0]); 3087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 3089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<256; ++i) 3090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik values[i][0] = 255; /* no transparency/tRNS chunk */ 3091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 'values' contains 256 ARGB values, but we only need 'npalette'. 3093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'npalette' will always be a power of 2: 2, 4, 16 or 256. In the low 3094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bit depth cases select colors at random, else it is difficult to have 3095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * a set of low bit depth palette test with any chance of a reasonable 3096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * range of colors. Do this by randomly permuting values into the low 3097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'npalette' entries using an XOR mask generated here. This also 3098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * permutes the npalette == 256 case in a potentially useful way (there is 3099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * no relationship between palette index and the color value therein!) 3100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette = store_write_palette(ps, npalette); 3102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<npalette; ++i) 3104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].alpha = values[i ^ selector[1]][0]; 3106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].red = values[i ^ selector[1]][1]; 3107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].green = values[i ^ selector[1]][2]; 3108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].blue = values[i ^ selector[1]][3]; 3109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return palette; 3112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Initialize a standard palette on a write stream. The 'do_tRNS' argument 3116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * indicates whether or not to also set the tRNS chunk. 3117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* TODO: the png_structp here can probably be 'const' in the future */ 3119b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3120b50c217251b086440efcdb273c22f86a06c80cbaChris Craikinit_standard_palette(png_store *ps, png_structp pp, png_infop pi, int npalette, 3121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_tRNS) 3122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette_entry *ppal = make_standard_palette(ps, npalette, do_tRNS); 3124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i; 3127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color palette[256]; 3128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set all entries to detect overread errors. */ 3130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<npalette; ++i) 3131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].red = ppal[i].red; 3133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].green = ppal[i].green; 3134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].blue = ppal[i].blue; 3135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Just in case fill in the rest with detectable values: */ 3138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; i<256; ++i) 3139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].red = palette[i].green = palette[i].blue = 42; 3140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_PLTE(pp, pi, palette, npalette); 3142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_tRNS) 3145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i, j; 3147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte tRNS[256]; 3148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set all the entries, but skip trailing opaque entries */ 3150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=j=0; i<npalette; ++i) 3151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((tRNS[i] = ppal[i].alpha) < 255) 3152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik j = i+1; 3153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Fill in the remainder with a detectable value: */ 3155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; i<256; ++i) 3156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tRNS[i] = 24; 3157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3158b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_WRITE_tRNS_SUPPORTED 3159b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (j > 0) 3160b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_set_tRNS(pp, pi, tRNS, j, 0/*color*/); 3161b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 3162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The number of passes is related to the interlace type. There was no libpng 3166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * API to determine this prior to 1.5, so we need an inquiry function: 3167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3168b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 3169b50c217251b086440efcdb273c22f86a06c80cbaChris Craiknpasses_from_interlace_type(png_const_structp pp, int interlace_type) 3170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (interlace_type) 3172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 3174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "invalid interlace type"); 3175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_INTERLACE_NONE: 3177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 3178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_INTERLACE_ADAM7: 3180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return PNG_INTERLACE_ADAM7_PASSES; 3181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3184b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic unsigned int 3185b50c217251b086440efcdb273c22f86a06c80cbaChris Craikbit_size(png_const_structp pp, png_byte colour_type, png_byte bit_depth) 3186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (colour_type) 3188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: png_error(pp, "invalid color type"); 3190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 0: return bit_depth; 3192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 2: return 3*bit_depth; 3194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 3: return bit_depth; 3196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 4: return 2*bit_depth; 3198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 6: return 4*bit_depth; 3200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define TRANSFORM_WIDTH 128U 3204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define TRANSFORM_ROWMAX (TRANSFORM_WIDTH*8U) 3205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define SIZE_ROWMAX (16*8U) /* 16 pixels, max 8 bytes each - 128 bytes */ 3206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define STANDARD_ROWMAX TRANSFORM_ROWMAX /* The larger of the two */ 3207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define SIZE_HEIGHTMAX 16 /* Maximum range of size images */ 3208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3209b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic size_t 3210b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_rowsize(png_const_structp pp, png_byte colour_type, 3211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth) 3212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (TRANSFORM_WIDTH * bit_size(pp, colour_type, bit_depth)) / 8; 3214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* transform_width(pp, colour_type, bit_depth) current returns the same number 3217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * every time, so just use a macro: 3218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define transform_width(pp, colour_type, bit_depth) TRANSFORM_WIDTH 3220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3221b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 3222b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_height(png_const_structp pp, png_byte colour_type, png_byte bit_depth) 3223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (bit_size(pp, colour_type, bit_depth)) 3225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 1: 3227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 2: 3228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 4: 3229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; /* Total of 128 pixels */ 3230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 8: 3232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 2; /* Total of 256 pixels/bytes */ 3233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 16: 3235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 512; /* Total of 65536 pixels */ 3236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 24: 3238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 32: 3239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 512; /* 65536 pixels */ 3240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 48: 3242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 64: 3243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 2048;/* 4 x 65536 pixels. */ 3244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define TRANSFORM_HEIGHTMAX 2048 3245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 3247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; /* Error, will be caught later */ 3248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 3252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following can only be defined here, now we have the definitions 3253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of the transform image sizes. 3254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3255b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 3256b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_width(png_const_structp pp, png_uint_32 id) 3257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 width = WIDTH_FROM_ID(id); 3259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(pp) 3260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (width == 0) 3262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik width = transform_width(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); 3263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return width; 3265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3267b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 3268b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_height(png_const_structp pp, png_uint_32 id) 3269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 height = HEIGHT_FROM_ID(id); 3271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (height == 0) 3273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik height = transform_height(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); 3274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return height; 3276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3278b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 3279b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_rowsize(png_const_structp pp, png_uint_32 id) 3280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 width = standard_width(pp, id); 3282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This won't overflow: */ 3284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik width *= bit_size(pp, COL_FROM_ID(id), DEPTH_FROM_ID(id)); 3285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (width + 7) / 8; 3286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 3288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3289b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3290b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX], 3291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type, png_byte bit_depth, png_uint_32 y) 3292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 v = y << 7; 3294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 i = 0; 3295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (bit_size(pp, colour_type, bit_depth)) 3297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 1: 3299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128/8) buffer[i] = (png_byte)(v & 0xff), v += 17, ++i; 3300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 2: 3303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128/4) buffer[i] = (png_byte)(v & 0xff), v += 33, ++i; 3304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 4: 3307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128/2) buffer[i] = (png_byte)(v & 0xff), v += 65, ++i; 3308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 8: 3311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 256 bytes total, 128 bytes in each row set as follows: */ 3312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128) buffer[i] = (png_byte)(v & 0xff), ++v, ++i; 3313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 16: 3316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Generate all 65536 pixel values in order, which includes the 8 bit 3317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * GA case as well as the 16 bit G case. 3318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128) 3320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[2*i] = (png_byte)((v>>8) & 0xff); 3322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[2*i+1] = (png_byte)(v & 0xff); 3323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++v; 3324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++i; 3325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 24: 3330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 65535 pixels, but rotate the values. */ 3331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128) 3332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Three bytes per pixel, r, g, b, make b by r^g */ 3334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[3*i+0] = (png_byte)((v >> 8) & 0xff); 3335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[3*i+1] = (png_byte)(v & 0xff); 3336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[3*i+2] = (png_byte)(((v >> 8) ^ v) & 0xff); 3337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++v; 3338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++i; 3339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 32: 3344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 65535 pixels, r, g, b, a; just replicate */ 3345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128) 3346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[4*i+0] = (png_byte)((v >> 8) & 0xff); 3348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[4*i+1] = (png_byte)(v & 0xff); 3349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[4*i+2] = (png_byte)((v >> 8) & 0xff); 3350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[4*i+3] = (png_byte)(v & 0xff); 3351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++v; 3352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++i; 3353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 48: 3358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* y is maximum 2047, giving 4x65536 pixels, make 'r' increase by 1 at 3359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * each pixel, g increase by 257 (0x101) and 'b' by 0x1111: 3360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128) 3362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 t = v++; 3364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[6*i+0] = (png_byte)((t >> 8) & 0xff); 3365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[6*i+1] = (png_byte)(t & 0xff); 3366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik t *= 257; 3367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[6*i+2] = (png_byte)((t >> 8) & 0xff); 3368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[6*i+3] = (png_byte)(t & 0xff); 3369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik t *= 17; 3370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[6*i+4] = (png_byte)((t >> 8) & 0xff); 3371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[6*i+5] = (png_byte)(t & 0xff); 3372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++i; 3373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 64: 3378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* As above in the 32 bit case. */ 3379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i<128) 3380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 t = v++; 3382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+0] = (png_byte)((t >> 8) & 0xff); 3383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+1] = (png_byte)(t & 0xff); 3384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+4] = (png_byte)((t >> 8) & 0xff); 3385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+5] = (png_byte)(t & 0xff); 3386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik t *= 257; 3387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+2] = (png_byte)((t >> 8) & 0xff); 3388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+3] = (png_byte)(t & 0xff); 3389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+6] = (png_byte)((t >> 8) & 0xff); 3390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik buffer[8*i+7] = (png_byte)(t & 0xff); 3391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++i; 3392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 3394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 3396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 3397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "internal error"); 3400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This is just to do the right cast - could be changed to a function to check 3403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'bd' but there isn't much point. 3404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define DEPTH(bd) ((png_byte)(1U << (bd))) 3406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3407b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* This is just a helper for compiling on minimal systems with no write 3408b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * interlacing support. If there is no write interlacing we can't generate test 3409b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * cases with interlace: 3410b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 3411b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_INTERLACING_SUPPORTED 3412b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define INTERLACE_LAST PNG_INTERLACE_LAST 3413b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define check_interlace_type(type) ((void)(type)) 3414b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else 3415b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define INTERLACE_LAST (PNG_INTERLACE_NONE+1) 3416b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define png_set_interlace_handling(a) (1) 3417b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 3418b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void 3419b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraricheck_interlace_type(int PNG_CONST interlace_type) 3420b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{ 3421b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (interlace_type != PNG_INTERLACE_NONE) 3422b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 3423b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* This is an internal error - --interlace tests should be skipped, not 3424b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * attempted. 3425b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 3426b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fprintf(stderr, "pngvalid: no interlace support\n"); 3427b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 3428b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 3429b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari} 3430b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif 3431b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 3432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Make a standardized image given a an image colour type, bit depth and 3433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * interlace type. The standard images have a very restricted range of 3434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * rows and heights and are used for testing transforms rather than image 3435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * layout details. See make_size_images below for a way to make images 3436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that test odd sizes along with the libpng interlace handling. 3437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3438b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3439b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, 3440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte PNG_CONST bit_depth, unsigned int palette_number, 3441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int interlace_type, png_const_charp name) 3442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik context(ps, fault); 3444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3445b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari check_interlace_type(interlace_type); 3446b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 3447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 3448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi; 3450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pp = set_store_for_write(ps, &pi, name); 3451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 h; 3452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* In the event of a problem return control to the Catch statement below 3454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to do the clean up - it is not possible to 'return' directly from a Try 3455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * block. 3456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp == NULL) 3458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 3459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik h = transform_height(pp, colour_type, bit_depth); 3461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), h, 3463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_depth, colour_type, interlace_type, 3464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 3465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_TEXT_SUPPORTED 3467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED) 3468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_zTXt 3469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 3470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define TEXT_COMPRESSION PNG_TEXT_COMPRESSION_NONE 3471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 3472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static char key[] = "image name"; /* must be writeable */ 3474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos; 3475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_text text; 3476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char copy[FILE_NAME_SIZE]; 3477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use a compressed text string to test the correct interaction of text 3479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * compression and IDAT compression. 3480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.compression = TEXT_COMPRESSION; 3482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.key = key; 3483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Yuck: the text must be writable! */ 3484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(copy, sizeof copy, 0, ps->wname); 3485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text = copy; 3486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text_length = pos; 3487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.itxt_length = 0; 3488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang = 0; 3489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang_key = 0; 3490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_text(pp, pi, &text, 1); 3492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 3494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type == 3) /* palette */ 3496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_standard_palette(ps, pp, pi, 1U << bit_depth, 1/*do tRNS*/); 3497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_info(pp, pi); 3499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_rowbytes(pp, pi) != 3501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_rowsize(pp, colour_type, bit_depth)) 3502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "row size incorrect"); 3503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 3505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Somewhat confusingly this must be called *after* png_write_info 3507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * because if it is called before, the information in *pp has not been 3508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * updated to reflect the interlaced image. 3509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npasses = png_set_interlace_handling(pp); 3511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int pass; 3512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (npasses != npasses_from_interlace_type(pp, interlace_type)) 3514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "write: png_set_interlace_handling failed"); 3515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (pass=0; pass<npasses; ++pass) 3517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 3519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<h; ++y) 3521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte buffer[TRANSFORM_ROWMAX]; 3523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_row(pp, buffer, colour_type, bit_depth, y); 3525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_row(pp, buffer); 3526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_TEXT_SUPPORTED 3531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static char key[] = "end marker"; 3533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static char comment[] = "end"; 3534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_text text; 3535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use a compressed text string to test the correct interaction of text 3537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * compression and IDAT compression. 3538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.compression = TEXT_COMPRESSION; 3540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.key = key; 3541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text = comment; 3542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text_length = (sizeof comment)-1; 3543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.itxt_length = 0; 3544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang = 0; 3545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang_key = 0; 3546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_text(pp, pi, &text, 1); 3548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 3550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_end(pp, pi); 3552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And store this under the appropriate id, then clean up. */ 3554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_storefile(ps, FILEID(colour_type, bit_depth, palette_number, 3555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik interlace_type, 0, 0, 0)); 3556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(ps); 3558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch(fault) 3561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use the png_store returned by the exception. This may help the compiler 3563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * because 'ps' is not used in this branch of the setjmp. Note that fault 3564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * and ps will always be the same value. 3565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(fault); 3567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3570b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3571b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_transform_images(png_store *ps) 3572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type = 0; 3574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth = 0; 3575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int palette_number = 0; 3576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is in case of errors. */ 3578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik safecat(ps->test, sizeof ps->test, 0, "make standard images"); 3579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use next_format to enumerate all the combinations we test, including 3581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * generating multiple low bit depth palette images. 3582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3583b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (next_format(&colour_type, &bit_depth, &palette_number, 0)) 3584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int interlace_type; 3586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (interlace_type = PNG_INTERLACE_NONE; 3588b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari interlace_type < INTERLACE_LAST; ++interlace_type) 3589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[FILE_NAME_SIZE]; 3591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_name(name, sizeof name, 0, colour_type, bit_depth, 3593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette_number, interlace_type, 0, 0, 0); 3594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_transform_image(ps, colour_type, bit_depth, palette_number, 3595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik interlace_type, name); 3596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following two routines use the PNG interlace support macros from 3601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png.h to interlace or deinterlace rows. 3602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3603b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3604b50c217251b086440efcdb273c22f86a06c80cbaChris Craikinterlace_row(png_bytep buffer, png_const_bytep imageRow, 3605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int pixel_size, png_uint_32 w, int pass) 3606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 xin, xout, xstep; 3608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Note that this can, trivially, be optimized to a memcpy on pass 7, the 3610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * code is presented this way to make it easier to understand. In practice 3611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * consult the code in the libpng source to see other ways of doing this. 3612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik xin = PNG_PASS_START_COL(pass); 3614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik xstep = 1U<<PNG_PASS_COL_SHIFT(pass); 3615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (xout=0; xin<w; xin+=xstep) 3617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pixel_copy(buffer, xout, imageRow, xin, pixel_size); 3619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++xout; 3620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 3624b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3625b50c217251b086440efcdb273c22f86a06c80cbaChris Craikdeinterlace_row(png_bytep buffer, png_const_bytep row, 3626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int pixel_size, png_uint_32 w, int pass) 3627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The inverse of the above, 'row' is part of row 'y' of the output image, 3629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in 'buffer'. The image is 'w' wide and this is pass 'pass', distribute 3630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the pixels of row into buffer and return the number written (to allow 3631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this to be checked). 3632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 xin, xout, xstep; 3634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik xout = PNG_PASS_START_COL(pass); 3636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik xstep = 1U<<PNG_PASS_COL_SHIFT(pass); 3637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (xin=0; xout<w; xout+=xstep) 3639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pixel_copy(buffer, xout, row, xin, pixel_size); 3641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++xin; 3642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 3645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Build a single row for the 'size' test images; this fills in only the 3647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * first bit_width bits of the sample row. 3648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3649b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3650b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksize_row(png_byte buffer[SIZE_ROWMAX], png_uint_32 bit_width, png_uint_32 y) 3651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* height is in the range 1 to 16, so: */ 3653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik y = ((y & 1) << 7) + ((y & 2) << 6) + ((y & 4) << 5) + ((y & 8) << 4); 3654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* the following ensures bits are set in small images: */ 3655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik y ^= 0xA5; 3656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (bit_width >= 8) 3658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *buffer++ = (png_byte)y++, bit_width -= 8; 3659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There may be up to 7 remaining bits, these go in the most significant 3661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bits of the byte. 3662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (bit_width > 0) 3664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 mask = (1U<<(8-bit_width))-1; 3666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *buffer = (png_byte)((*buffer & mask) | (y & ~mask)); 3667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3670b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3671b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, 3672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte PNG_CONST bit_depth, int PNG_CONST interlace_type, 3673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 PNG_CONST w, png_uint_32 PNG_CONST h, 3674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int PNG_CONST do_interlace) 3675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik context(ps, fault); 3677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3678b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* At present libpng does not support the write of an interlaced image unless 3679b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * PNG_WRITE_INTERLACING_SUPPORTED, even with do_interlace so the code here 3680b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * does the pixel interlace itself, so: 3681b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 3682b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari check_interlace_type(interlace_type); 3683b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 3684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 3685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi; 3687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pp; 3688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int pixel_size; 3689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Make a name and get an appropriate id for the store: */ 3691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[FILE_NAME_SIZE]; 3692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/, 3693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik interlace_type, w, h, do_interlace); 3694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_name_from_id(name, sizeof name, 0, id); 3696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp = set_store_for_write(ps, &pi, name); 3697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* In the event of a problem return control to the Catch statement below 3699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to do the clean up - it is not possible to 'return' directly from a Try 3700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * block. 3701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp == NULL) 3703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 3704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type, 3706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 3707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_TEXT_SUPPORTED 3709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static char key[] = "image name"; /* must be writeable */ 3711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos; 3712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_text text; 3713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char copy[FILE_NAME_SIZE]; 3714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use a compressed text string to test the correct interaction of text 3716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * compression and IDAT compression. 3717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.compression = TEXT_COMPRESSION; 3719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.key = key; 3720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Yuck: the text must be writable! */ 3721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(copy, sizeof copy, 0, ps->wname); 3722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text = copy; 3723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text_length = pos; 3724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.itxt_length = 0; 3725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang = 0; 3726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang_key = 0; 3727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_text(pp, pi, &text, 1); 3729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 3731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type == 3) /* palette */ 3733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/); 3734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_info(pp, pi); 3736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Calculate the bit size, divide by 8 to get the byte size - this won't 3738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * overflow because we know the w values are all small enough even for 3739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * a system where 'unsigned int' is only 16 bits. 3740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pixel_size = bit_size(pp, colour_type, bit_depth); 3742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_rowbytes(pp, pi) != ((w * pixel_size) + 7) / 8) 3743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "row size incorrect"); 3744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 3746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npasses = npasses_from_interlace_type(pp, interlace_type); 3748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 3749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int pass; 3750b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_WRITE_FILTER_SUPPORTED 3751b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int nfilter = PNG_FILTER_VALUE_LAST; 3752b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 3753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte image[16][SIZE_ROWMAX]; 3754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* To help consistent error detection make the parts of this buffer 3756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that aren't set below all '1': 3757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(image, 0xff, sizeof image); 3759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!do_interlace && npasses != png_set_interlace_handling(pp)) 3761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "write: png_set_interlace_handling failed"); 3762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Prepare the whole image first to avoid making it 7 times: */ 3764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<h; ++y) 3765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_row(image[y], w * pixel_size, y); 3766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (pass=0; pass<npasses; ++pass) 3768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following two are for checking the macros: */ 3770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 wPass = PNG_PASS_COLS(w, pass); 3771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If do_interlace is set we don't call png_write_row for every 3773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * row because some of them are empty. In fact, for a 1x1 image, 3774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * most of them are empty! 3775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<h; ++y) 3777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_bytep row = image[y]; 3779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte tempRow[SIZE_ROWMAX]; 3780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If do_interlace *and* the image is interlaced we 3782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * need a reduced interlace row; this may be reduced 3783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to empty. 3784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_interlace && interlace_type == PNG_INTERLACE_ADAM7) 3786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The row must not be written if it doesn't exist, notice 3788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that there are two conditions here, either the row isn't 3789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * ever in the pass or the row would be but isn't wide 3790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * enough to contribute any pixels. In fact the wPass test 3791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * can be used to skip the whole y loop in this case. 3792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (PNG_ROW_IN_INTERLACE_PASS(y, pass) && wPass > 0) 3794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set to all 1's for error detection (libpng tends to 3796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * set unset things to 0). 3797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(tempRow, 0xff, sizeof tempRow); 3799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik interlace_row(tempRow, row, pixel_size, w, pass); 3800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row = tempRow; 3801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 3803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik continue; 3804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3806b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_WRITE_FILTER_SUPPORTED 3807b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Only get to here if the row has some pixels in it, set the 3808b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * filters to 'all' for the very first row and thereafter to a 3809b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * single filter. It isn't well documented, but png_set_filter 3810b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * does accept a filter number (per the spec) as well as a bit 3811b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * mask. 3812b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 3813b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * The apparent wackiness of decrementing nfilter rather than 3814b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * incrementing is so that Paeth gets used in all images bigger 3815b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * than 1 row - it's the tricky one. 3816b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 3817b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_set_filter(pp, 0/*method*/, 3818b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari nfilter >= PNG_FILTER_VALUE_LAST ? PNG_ALL_FILTERS : nfilter); 3819b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 3820b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (nfilter-- == 0) 3821b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari nfilter = PNG_FILTER_VALUE_LAST-1; 3822b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 3823b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 3824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_row(pp, row); 3825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_TEXT_SUPPORTED 3830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static char key[] = "end marker"; 3832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static char comment[] = "end"; 3833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_text text; 3834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use a compressed text string to test the correct interaction of text 3836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * compression and IDAT compression. 3837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.compression = TEXT_COMPRESSION; 3839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.key = key; 3840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text = comment; 3841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.text_length = (sizeof comment)-1; 3842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.itxt_length = 0; 3843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang = 0; 3844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik text.lang_key = 0; 3845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_text(pp, pi, &text, 1); 3847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 3849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_end(pp, pi); 3851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And store this under the appropriate id, then clean up. */ 3853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_storefile(ps, id); 3854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(ps); 3856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch(fault) 3859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use the png_store returned by the exception. This may help the compiler 3861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * because 'ps' is not used in this branch of the setjmp. Note that fault 3862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * and ps will always be the same value. 3863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(fault); 3865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3868b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3869b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_size(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo, 3870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int PNG_CONST bdhi) 3871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; bdlo <= bdhi; ++bdlo) 3873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 width; 3875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (width = 1; width <= 16; ++width) 3877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 height; 3879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (height = 1; height <= 16; ++height) 3881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The four combinations of DIY interlace and interlace or not - 3883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * no interlace + DIY should be identical to no interlace with 3884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng doing it. 3885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_NONE, 3887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik width, height, 0); 3888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_NONE, 3889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik width, height, 1); 3890b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_WRITE_INTERLACING_SUPPORTED 3891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, 3892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik width, height, 0); 3893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size_image(ps, colour_type, DEPTH(bdlo), PNG_INTERLACE_ADAM7, 3894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik width, height, 1); 3895b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 3896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 3899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3901b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3902b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_size_images(png_store *ps) 3903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is in case of errors. */ 3905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik safecat(ps->test, sizeof ps->test, 0, "make size images"); 3906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Arguments are colour_type, low bit depth, high bit depth 3908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size(ps, 0, 0, WRITE_BDHI); 3910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size(ps, 2, 3, WRITE_BDHI); 3911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size(ps, 3, 0, 3 /*palette: max 8 bits*/); 3912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size(ps, 4, 3, WRITE_BDHI); 3913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size(ps, 6, 3, WRITE_BDHI); 3914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 3917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Return a row based on image id and 'y' for checking: */ 3918b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3919b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_row(png_const_structp pp, png_byte std[STANDARD_ROWMAX], 3920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 id, png_uint_32 y) 3921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (WIDTH_FROM_ID(id) == 0) 3923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_row(pp, std, COL_FROM_ID(id), DEPTH_FROM_ID(id), y); 3924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 3925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_row(std, WIDTH_FROM_ID(id) * bit_size(pp, COL_FROM_ID(id), 3926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik DEPTH_FROM_ID(id)), y); 3927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 3929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Tests - individual test cases */ 3931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Like 'make_standard' but errors are deliberately introduced into the calls 3932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to ensure that they get detected - it should not be possible to write an 3933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * invalid image with libpng! 3934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* TODO: the 'set' functions can probably all be made to take a 3936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_const_structp rather than a modifiable one. 3937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 3938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_WARNINGS_SUPPORTED 3939b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3940b50c217251b086440efcdb273c22f86a06c80cbaChris CraiksBIT0_error_fn(png_structp pp, png_infop pi) 3941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 0 is invalid... */ 3943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color_8 bad; 3944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bad.red = bad.green = bad.blue = bad.gray = bad.alpha = 0; 3945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_sBIT(pp, pi, &bad); 3946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3948b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3949b50c217251b086440efcdb273c22f86a06c80cbaChris CraiksBIT_error_fn(png_structp pp, png_infop pi) 3950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth; 3952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color_8 bad; 3953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_color_type(pp, pi) == PNG_COLOR_TYPE_PALETTE) 3955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_depth = 8; 3956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 3958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_depth = png_get_bit_depth(pp, pi); 3959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now we know the bit depth we can easily generate an invalid sBIT entry */ 3961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bad.red = bad.green = bad.blue = bad.gray = bad.alpha = 3962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (png_byte)(bit_depth+1); 3963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_sBIT(pp, pi, &bad); 3964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 3965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3966b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic PNG_CONST struct 3967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik void (*fn)(png_structp, png_infop); 3969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *msg; 3970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int warning :1; /* the error is a warning... */ 3971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} error_test[] = 3972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* no warnings makes these errors undetectable. */ 3974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { sBIT0_error_fn, "sBIT(0): failed to detect error", 1 }, 3975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { sBIT_error_fn, "sBIT(too big): failed to detect error", 1 }, 3976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik }; 3977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3978b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 3979b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_error(png_store* volatile psIn, png_byte PNG_CONST colour_type, 3980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth, int interlace_type, int test, png_const_charp name) 3981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 3982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store * volatile ps = psIn; 3983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik context(ps, fault); 3985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3986b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari check_interlace_type(interlace_type); 3987b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 3988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 3989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pp; 3991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi; 3992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp = set_store_for_write(ps, &pi, name); 3994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp == NULL) 3996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 3997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 3998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_IHDR(pp, pi, transform_width(pp, colour_type, bit_depth), 3999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_height(pp, colour_type, bit_depth), bit_depth, colour_type, 4000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 4001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type == 3) /* palette */ 4003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/); 4004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Time for a few errors; these are in various optional chunks, the 4006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * standard tests test the standard chunks pretty well. 4007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define exception__prev exception_prev_1 4009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define exception__env exception_env_1 4010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 4011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Expect this to throw: */ 4013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->expect_error = !error_test[test].warning; 4014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->expect_warning = error_test[test].warning; 4015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->saw_warning = 0; 4016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik error_test[test].fn(pp, pi); 4017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Normally the error is only detected here: */ 4019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_info(pp, pi); 4020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And handle the case where it was only a warning: */ 4022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (ps->expect_warning && ps->saw_warning) 4023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 4024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If we get here there is a problem, we have success - no error or 4026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * no warning - when we shouldn't have success. Log an error. 4027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(ps, pp, error_test[test].msg, 1 /*error*/); 4029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch (fault) 4032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps = fault; /* expected exit, make sure ps is not clobbered */ 4033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef exception__prev 4034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef exception__env 4035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And clear these flags */ 4037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->expect_error = 0; 4038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ps->expect_warning = 0; 4039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now write the whole image, just to make sure that the detected, or 4041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * undetected, errro has not created problems inside libpng. 4042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_rowbytes(pp, pi) != 4044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_rowsize(pp, colour_type, bit_depth)) 4045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "row size incorrect"); 4046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 h = transform_height(pp, colour_type, bit_depth); 4050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npasses = png_set_interlace_handling(pp); 4051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int pass; 4052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (npasses != npasses_from_interlace_type(pp, interlace_type)) 4054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "write: png_set_interlace_handling failed"); 4055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (pass=0; pass<npasses; ++pass) 4057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 4059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<h; ++y) 4061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte buffer[TRANSFORM_ROWMAX]; 4063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_row(pp, buffer, colour_type, bit_depth, y); 4065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_row(pp, buffer); 4066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_write_end(pp, pi); 4071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following deletes the file that was just written. */ 4073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(ps); 4074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch(fault) 4077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(fault); 4079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4082b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 4083b50c217251b086440efcdb273c22f86a06c80cbaChris Craikmake_errors(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type, 4084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int bdlo, int PNG_CONST bdhi) 4085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; bdlo <= bdhi; ++bdlo) 4087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int interlace_type; 4089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (interlace_type = PNG_INTERLACE_NONE; 4091b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari interlace_type < INTERLACE_LAST; ++interlace_type) 4092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int test; 4094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[FILE_NAME_SIZE]; 4095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_name(name, sizeof name, 0, colour_type, 1<<bdlo, 0, 4097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik interlace_type, 0, 0, 0); 4098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (test=0; test<(sizeof error_test)/(sizeof error_test[0]); ++test) 4100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_error(&pm->this, colour_type, DEPTH(bdlo), interlace_type, 4102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test, name); 4103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 4105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 4106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; /* keep going */ 4111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4112b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* PNG_WARNINGS_SUPPORTED */ 4113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4114b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4115b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_error_test(png_modifier *pm) 4116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_WARNINGS_SUPPORTED /* else there are no cases that work! */ 4118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Need to do this here because we just write in this test. */ 4119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik safecat(pm->this.test, sizeof pm->this.test, 0, "error test"); 4120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!make_errors(pm, 0, 0, WRITE_BDHI)) 4122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 4123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!make_errors(pm, 2, 3, WRITE_BDHI)) 4125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 4126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!make_errors(pm, 3, 0, 3)) 4128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 4129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!make_errors(pm, 4, 3, WRITE_BDHI)) 4131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 4132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!make_errors(pm, 6, 3, WRITE_BDHI)) 4134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 4135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 4136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(pm) 4137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 4138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This is just to validate the internal PNG formatting code - if this fails 4141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * then the warning messages the library outputs will probably be garbage. 4142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4143b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4144b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_formatting_test(png_store *volatile ps) 4145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_TIME_RFC1123_SUPPORTED 4147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The handle into the formatting code is the RFC1123 support; this test does 4148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * nothing if that is compiled out. 4149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik context(ps, fault); 4151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 4153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_charp correct = "29 Aug 2079 13:53:60 +0000"; 4155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_charp result; 4156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if PNG_LIBPNG_VER >= 10600 4157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char timestring[29]; 4158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 4159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pp; 4160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_time pt; 4161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp = set_store_for_write(ps, NULL, "libpng formatting test"); 4163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pp == NULL) 4165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw ps; 4166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Arbitrary settings: */ 4169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pt.year = 2079; 4170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pt.month = 8; 4171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pt.day = 29; 4172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pt.hour = 13; 4173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pt.minute = 53; 4174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pt.second = 60; /* a leap second */ 4175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if PNG_LIBPNG_VER < 10600 4177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik result = png_convert_to_rfc1123(pp, &pt); 4178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 4179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_convert_to_rfc1123_buffer(timestring, &pt)) 4180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik result = timestring; 4181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik result = NULL; 4184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 4185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (result == NULL) 4187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "png_convert_to_rfc1123 failed"); 4188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (strcmp(result, correct) != 0) 4190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 4192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[128]; 4193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "png_convert_to_rfc1123("); 4195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, correct); 4196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, ") returned: '"); 4197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, result); 4198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "'"); 4199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 4201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(ps); 4204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch(fault) 4207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_write_reset(fault); 4209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 4211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(ps) 4212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 4213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED 4216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Because we want to use the same code in both the progressive reader and the 4217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * sequential reader it is necessary to deal with the fact that the progressive 4218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * reader callbacks only have one parameter (png_get_progressive_ptr()), so this 4219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * must contain all the test parameters and all the local variables directly 4220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * accessible to the sequential reader implementation. 4221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 4222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The technique adopted is to reinvent part of what Dijkstra termed a 4223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'display'; an array of pointers to the stack frames of enclosing functions so 4224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that a nested function definition can access the local (C auto) variables of 4225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the functions that contain its definition. In fact C provides the first 4226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * pointer (the local variables - the stack frame pointer) and the last (the 4227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * global variables - the BCPL global vector typically implemented as global 4228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * addresses), this code requires one more pointer to make the display - the 4229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * local variables (and function call parameters) of the function that actually 4230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * invokes either the progressive or sequential reader. 4231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 4232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Perhaps confusingly this technique is confounded with classes - the 4233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'standard_display' defined here is sub-classed as the 'gamma_display' below. 4234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * A gamma_display is a standard_display, taking advantage of the ANSI-C 4235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * requirement that the pointer to the first member of a structure must be the 4236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * same as the pointer to the structure. This allows us to reuse standard_ 4237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * functions in the gamma test code; something that could not be done with 4238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * nested functions! 4239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4240b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct standard_display 4241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_store* ps; /* Test parameters (passed to the function) */ 4243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type; 4244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth; 4245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte red_sBIT; /* Input data sBIT values. */ 4246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte green_sBIT; 4247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte blue_sBIT; 4248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte alpha_sBIT; 4249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int interlace_type; 4250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 id; /* Calculated file ID */ 4251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 w; /* Width of image */ 4252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 h; /* Height of image */ 4253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npasses; /* Number of interlaced passes */ 4254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 pixel_size; /* Width of one pixel in bits */ 4255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 bit_width; /* Width of output row in bits */ 4256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t cbRow; /* Bytes in a row of the output image */ 4257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_interlace; /* Do interlacing internally */ 4258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int is_transparent; /* Transparency information was present. */ 4259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int speed; /* Doing a speed test */ 4260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int use_update_info;/* Call update_info, not start_image */ 4261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct 4262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_16 red; 4264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_16 green; 4265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_16 blue; 4266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } transparent; /* The transparent color, if set. */ 4267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npalette; /* Number of entries in the palette. */ 4268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette 4269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette; 4270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} standard_display; 4271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4272b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4273b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_display_init(standard_display *dp, png_store* ps, png_uint_32 id, 4274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_interlace, int use_update_info) 4275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(dp, 0, sizeof *dp); 4277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->ps = ps; 4279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->colour_type = COL_FROM_ID(id); 4280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->bit_depth = DEPTH_FROM_ID(id); 4281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->bit_depth < 1 || dp->bit_depth > 16) 4282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik internal_error(ps, "internal: bad bit depth"); 4283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->colour_type == 3) 4284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = 8; 4285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = 4287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->bit_depth; 4288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->interlace_type = INTERLACE_FROM_ID(id); 4289b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari check_interlace_type(dp->interlace_type); 4290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->id = id; 4291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* All the rest are filled in after the read_info: */ 4292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->w = 0; 4293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->h = 0; 4294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->npasses = 0; 4295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pixel_size = 0; 4296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->bit_width = 0; 4297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->cbRow = 0; 4298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->do_interlace = do_interlace; 4299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->is_transparent = 0; 4300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->speed = ps->speed; 4301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->use_update_info = use_update_info; 4302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->npalette = 0; 4303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Preset the transparent color to black: */ 4304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(&dp->transparent, 0, sizeof dp->transparent); 4305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Preset the palette to full intensity/opaque througout: */ 4306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(dp->palette, 0xff, sizeof dp->palette); 4307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Initialize the palette fields - this must be done later because the palette 4310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * comes from the particular png_store_file that is selected. 4311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4312b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4313b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_palette_init(standard_display *dp) 4314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette_entry *palette = store_current_palette(dp->ps, &dp->npalette); 4316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The remaining entries remain white/opaque. */ 4318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->npalette > 0) 4319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i = dp->npalette; 4321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memcpy(dp->palette, palette, i * sizeof *palette); 4322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for a non-opaque palette entry: */ 4324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (--i >= 0) 4325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (palette[i].alpha < 255) 4326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 4327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef __GNUC__ 4329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* GCC can't handle the more obviously optimizable version. */ 4330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (i >= 0) 4331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->is_transparent = 1; 4332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->is_transparent = 0; 4334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 4335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->is_transparent = (i >= 0); 4336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 4337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Utility to read the palette from the PNG file and convert it into 4341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * store_palette format. This returns 1 if there is any transparency in the 4342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * palette (it does not check for a transparent colour in the non-palette case.) 4343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4344b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 4345b50c217251b086440efcdb273c22f86a06c80cbaChris Craikread_palette(store_palette palette, int *npalette, png_const_structp pp, 4346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi) 4347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_colorp pal; 4349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_bytep trans_alpha; 4350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int num; 4351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pal = 0; 4353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *npalette = -1; 4354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_PLTE(pp, pi, &pal, npalette) & PNG_INFO_PLTE) 4356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i = *npalette; 4358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (i <= 0 || i > 256) 4360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: invalid PLTE count"); 4361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (--i >= 0) 4363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].red = pal[i].red; 4365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].green = pal[i].green; 4366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].blue = pal[i].blue; 4367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Mark the remainder of the entries with a flag value (other than 4370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * white/opaque which is the flag value stored above.) 4371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(palette + *npalette, 126, (256-*npalette) * sizeof *palette); 4373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* !png_get_PLTE */ 4376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (*npalette != (-1)) 4378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: invalid PLTE result"); 4379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* But there is no palette, so record this: */ 4380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *npalette = 0; 4381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(palette, 113, sizeof (store_palette)); 4382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik trans_alpha = 0; 4385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik num = 2; /* force error below */ 4386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((png_get_tRNS(pp, pi, &trans_alpha, &num, 0) & PNG_INFO_tRNS) != 0 && 4387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (trans_alpha != NULL || num != 1/*returns 1 for a transparent color*/) && 4388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Oops, if a palette tRNS gets expanded png_read_update_info (at least so 4389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * far as 1.5.4) does not remove the trans_alpha pointer, only num_trans, 4390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * so in the above call we get a success, we get a pointer (who knows what 4391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to) and we get num_trans == 0: 4392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik !(trans_alpha != NULL && num == 0)) /* TODO: fix this in libpng. */ 4394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i; 4396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Any of these are crash-worthy - given the implementation of 4398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_get_tRNS up to 1.5 an app won't crash if it just checks the 4399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * result above and fails to check that the variables it passed have 4400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * actually been filled in! Note that if the app were to pass the 4401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * last, png_color_16p, variable too it couldn't rely on this. 4402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (trans_alpha == NULL || num <= 0 || num > 256 || num > *npalette) 4404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: unexpected png_get_tRNS (palette) result"); 4405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<num; ++i) 4407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].alpha = trans_alpha[i]; 4408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (num=*npalette; i<num; ++i) 4410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].alpha = 255; 4411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; i<256; ++i) 4413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].alpha = 33; /* flag value */ 4414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; /* transparency */ 4416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* No palette transparency - just set the alpha channel to opaque. */ 4421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i; 4422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0, num=*npalette; i<num; ++i) 4424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].alpha = 255; 4425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; i<256; ++i) 4427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].alpha = 55; /* flag value */ 4428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; /* no transparency */ 4430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Utility to validate the palette if it should not have changed (the 4434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * non-transform case). 4435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4436b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4437b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_palette_validate(standard_display *dp, png_const_structp pp, 4438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi) 4439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npalette; 4441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette palette; 4442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (read_palette(palette, &npalette, pp, pi) != dp->is_transparent) 4444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: palette transparency changed"); 4445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (npalette != dp->npalette) 4447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 4449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[64]; 4450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "validate: palette size changed: "); 4452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, dp->npalette); 4453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " -> "); 4454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, npalette); 4455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 4456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i = npalette; /* npalette is aliased */ 4460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (--i >= 0) 4462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (palette[i].red != dp->palette[i].red || 4463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].green != dp->palette[i].green || 4464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].blue != dp->palette[i].blue || 4465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette[i].alpha != dp->palette[i].alpha) 4466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: PLTE or tRNS chunk changed"); 4467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* By passing a 'standard_display' the progressive callbacks can be used 4471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * directly by the sequential code, the functions suffixed "_imp" are the 4472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * implementations, the functions without the suffix are the callbacks. 4473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 4474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The code for the info callback is split into two because this callback calls 4475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_read_update_info or png_start_read_image and what gets called depends on 4476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * whether the info needs updating (we want to test both calls in pngvalid.) 4477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4478b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4479b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_info_part1(standard_display *dp, png_structp pp, png_infop pi) 4480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_bit_depth(pp, pi) != dp->bit_depth) 4482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: bit depth changed"); 4483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_color_type(pp, pi) != dp->colour_type) 4485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: color type changed"); 4486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_filter_type(pp, pi) != PNG_FILTER_TYPE_BASE) 4488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: filter type changed"); 4489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_interlace_type(pp, pi) != dp->interlace_type) 4491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: interlacing changed"); 4492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_compression_type(pp, pi) != PNG_COMPRESSION_TYPE_BASE) 4494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: compression type changed"); 4495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->w = png_get_image_width(pp, pi); 4497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->w != standard_width(pp, dp->id)) 4499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: image width changed"); 4500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->h = png_get_image_height(pp, pi); 4502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->h != standard_height(pp, dp->id)) 4504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: image height changed"); 4505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Record (but don't check at present) the input sBIT according to the colour 4507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * type information. 4508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color_8p sBIT = 0; 4511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_sBIT(pp, pi, &sBIT) & PNG_INFO_sBIT) 4513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int sBIT_invalid = 0; 4515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sBIT == 0) 4517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: unexpected png_get_sBIT result"); 4518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->colour_type & PNG_COLOR_MASK_COLOR) 4520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sBIT->red == 0 || sBIT->red > dp->bit_depth) 4522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sBIT_invalid = 1; 4523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->red_sBIT = sBIT->red; 4525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sBIT->green == 0 || sBIT->green > dp->bit_depth) 4527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sBIT_invalid = 1; 4528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->green_sBIT = sBIT->green; 4530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sBIT->blue == 0 || sBIT->blue > dp->bit_depth) 4532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sBIT_invalid = 1; 4533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->blue_sBIT = sBIT->blue; 4535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* !COLOR */ 4538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sBIT->gray == 0 || sBIT->gray > dp->bit_depth) 4540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sBIT_invalid = 1; 4541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->blue_sBIT = dp->green_sBIT = dp->red_sBIT = sBIT->gray; 4543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* All 8 bits in tRNS for a palette image are significant - see the 4546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * spec. 4547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->colour_type & PNG_COLOR_MASK_ALPHA) 4549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sBIT->alpha == 0 || sBIT->alpha > dp->bit_depth) 4551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sBIT_invalid = 1; 4552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->alpha_sBIT = sBIT->alpha; 4554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sBIT_invalid) 4557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: sBIT value out of range"); 4558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Important: this is validating the value *before* any transforms have been 4562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * put in place. It doesn't matter for the standard tests, where there are 4563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * no transforms, but it does for other tests where rowbytes may change after 4564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_read_update_info. 4565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_rowbytes(pp, pi) != standard_rowsize(pp, dp->id)) 4567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: row size changed"); 4568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Validate the colour type 3 palette (this can be present on other color 4570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * types.) 4571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_palette_validate(dp, pp, pi); 4573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* In any case always check for a tranparent color (notice that the 4575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * colour type 3 case must not give a successful return on the get_tRNS call 4576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * with these arguments!) 4577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color_16p trans_color = 0; 4580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (png_get_tRNS(pp, pi, 0, 0, &trans_color) & PNG_INFO_tRNS) 4582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (trans_color == 0) 4584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: unexpected png_get_tRNS (color) result"); 4585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (dp->colour_type) 4587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 0: 4589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transparent.red = dp->transparent.green = dp->transparent.blue = 4590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik trans_color->gray; 4591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->is_transparent = 1; 4592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 4593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 2: 4595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transparent.red = trans_color->red; 4596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transparent.green = trans_color->green; 4597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transparent.blue = trans_color->blue; 4598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->is_transparent = 1; 4599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 4600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 3: 4602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Not expected because it should result in the array case 4603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * above. 4604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: unexpected png_get_tRNS result"); 4606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 4607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 4609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: invalid tRNS chunk with alpha image"); 4610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Read the number of passes - expected to match the value used when 4615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * creating the image (interlaced or not). This has the side effect of 4616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * turning on interlace handling (if do_interlace is not set.) 4617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->npasses = npasses_from_interlace_type(pp, dp->interlace_type); 4619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!dp->do_interlace && dp->npasses != png_set_interlace_handling(pp)) 4620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "validate: file changed interlace type"); 4621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Caller calls png_read_update_info or png_start_read_image now, then calls 4623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * part2. 4624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This must be called *after* the png_read_update_info call to get the correct 4628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'rowbytes' value, otherwise png_get_rowbytes will refer to the untransformed 4629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * image. 4630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4631b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4632b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_info_part2(standard_display *dp, png_const_structp pp, 4633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_infop pi, int nImages) 4634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Record cbRow now that it can be found. */ 4636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pixel_size = bit_size(pp, png_get_color_type(pp, pi), 4637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_get_bit_depth(pp, pi)); 4638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->bit_width = png_get_image_width(pp, pi) * dp->pixel_size; 4639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->cbRow = png_get_rowbytes(pp, pi); 4640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Validate the rowbytes here again. */ 4642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->cbRow != (dp->bit_width+7)/8) 4643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "bad png_get_rowbytes calculation"); 4644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Then ensure there is enough space for the output image(s). */ 4646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_ensure_image(dp->ps, pp, nImages, dp->cbRow, dp->h); 4647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4649b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4650b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_info_imp(standard_display *dp, png_structp pp, png_infop pi, 4651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int nImages) 4652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Note that the validation routine has the side effect of turning on 4654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * interlace handling in the subsequent code. 4655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_part1(dp, pp, pi); 4657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And the info callback has to call this (or png_read_update_info - see 4659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * below in the png_modifier code for that variant. 4660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->use_update_info) 4662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For debugging the effect of multiple calls: */ 4664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i = dp->use_update_info; 4665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (i-- > 0) 4666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_update_info(pp, pi); 4667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_start_read_image(pp); 4671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Validate the height, width and rowbytes plus ensure that sufficient buffer 4673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * exists for decoding the image. 4674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_part2(dp, pp, pi, nImages); 4676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4678b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 4679b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_info(png_structp pp, png_infop pi) 4680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display *dp = voidcast(standard_display*, 4682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_get_progressive_ptr(pp)); 4683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Call with nImages==1 because the progressive reader can only produce one 4685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * image. 4686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_imp(dp, pp, pi, 1 /*only one image*/); 4688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4690b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 4691b50c217251b086440efcdb273c22f86a06c80cbaChris Craikprogressive_row(png_structp ppIn, png_bytep new_row, png_uint_32 y, int pass) 4692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 4694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST standard_display *dp = voidcast(standard_display*, 4695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_get_progressive_ptr(pp)); 4696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* When handling interlacing some rows will be absent in each pass, the 4698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * callback still gets called, but with a NULL pointer. This is checked 4699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in the 'else' clause below. We need our own 'cbRow', but we can't call 4700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_get_rowbytes because we got no info structure. 4701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (new_row != NULL) 4703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_bytep row; 4705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* In the case where the reader doesn't do the interlace it gives 4707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * us the y in the sub-image: 4708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->do_interlace && dp->interlace_type == PNG_INTERLACE_ADAM7) 4710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED 4712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use this opportunity to validate the png 'current' APIs: */ 4713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (y != png_get_current_row_number(pp)) 4714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "png_get_current_row_number is broken"); 4715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pass != png_get_current_pass_number(pp)) 4717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "png_get_current_pass_number is broken"); 4718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 4719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik y = PNG_ROW_FROM_PASS_ROW(y, pass); 4721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Validate this just in case. */ 4724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (y >= dp->h) 4725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "invalid y to progressive row callback"); 4726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row = store_image_row(dp->ps, pp, 0, y); 4728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_INTERLACING_SUPPORTED 4730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Combine the new row into the old: */ 4731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->do_interlace) 4732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->interlace_type == PNG_INTERLACE_ADAM7) 4734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik deinterlace_row(row, new_row, dp->pixel_size, dp->w, pass); 4735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik row_copy(row, new_row, dp->pixel_size * dp->w); 4737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_progressive_combine_row(pp, row, new_row); 4740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_INTERLACING_SUPPORTED */ 4741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_INTERLACING_SUPPORTED 4744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (dp->interlace_type == PNG_INTERLACE_ADAM7 && 4745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_ROW_IN_INTERLACE_PASS(y, pass) && 4746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_PASS_COLS(dp->w, pass) > 0) 4747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "missing row in progressive de-interlacing"); 4748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_INTERLACING_SUPPORTED */ 4749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4751b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4752b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksequential_row(standard_display *dp, png_structp pp, png_infop pi, 4753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int iImage, PNG_CONST int iDisplay) 4754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int npasses = dp->npasses; 4756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int do_interlace = dp->do_interlace && 4757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->interlace_type == PNG_INTERLACE_ADAM7; 4758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 height = standard_height(pp, dp->id); 4759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 width = standard_width(pp, dp->id); 4760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_store* ps = dp->ps; 4761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int pass; 4762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (pass=0; pass<npasses; ++pass) 4764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 4766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 wPass = PNG_PASS_COLS(width, pass); 4767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<height; ++y) 4769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_interlace) 4771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* wPass may be zero or this row may not be in this pass. 4773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_read_row must not be called in either case. 4774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (wPass > 0 && PNG_ROW_IN_INTERLACE_PASS(y, pass)) 4776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Read the row into a pair of temporary buffers, then do the 4778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * merge here into the output rows. 4779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte row[STANDARD_ROWMAX], display[STANDARD_ROWMAX]; 4781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following aids (to some extent) error detection - we can 4783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * see where png_read_row wrote. Use opposite values in row and 4784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * display to make this easier. Don't use 0xff (which is used in 4785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the image write code to fill unused bits) or 0 (which is a 4786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * likely value to overwrite unused bits with). 4787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(row, 0xc5, sizeof row); 4789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(display, 0x5c, sizeof display); 4790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_row(pp, row, display); 4792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (iImage >= 0) 4794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik deinterlace_row(store_image_row(ps, pp, iImage, y), row, 4795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pixel_size, dp->w, pass); 4796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (iDisplay >= 0) 4798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik deinterlace_row(store_image_row(ps, pp, iDisplay, y), display, 4799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pixel_size, dp->w, pass); 4800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_row(pp, 4804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik iImage >= 0 ? store_image_row(ps, pp, iImage, y) : NULL, 4805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik iDisplay >= 0 ? store_image_row(ps, pp, iDisplay, y) : NULL); 4806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And finish the read operation (only really necessary if the caller wants 4810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to find additional data in png_info from chunks after the last IDAT.) 4811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_end(pp, pi); 4813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_TEXT_SUPPORTED 4816b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4817b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_check_text(png_const_structp pp, png_const_textp tp, 4818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_charp keyword, png_const_charp text) 4819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[1024]; 4821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = safecat(msg, sizeof msg, 0, "text: "); 4822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t ok; 4823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, keyword); 4825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, ": "); 4826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ok = pos; 4827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->compression != TEXT_COMPRESSION) 4829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char buf[64]; 4831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(buf, "compression [%d->%d], ", TEXT_COMPRESSION, 4833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tp->compression); 4834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, buf); 4835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->key == NULL || strcmp(tp->key, keyword) != 0) 4838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "keyword \""); 4840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->key != NULL) 4841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, tp->key); 4843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "\", "); 4844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "null, "); 4848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->text == NULL) 4851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "text lost, "); 4852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->text_length != strlen(text)) 4856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char buf[64]; 4858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(buf, "text length changed[%lu->%lu], ", 4859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)strlen(text), (unsigned long)tp->text_length); 4860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, buf); 4861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (strcmp(tp->text, text) != 0) 4864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "text becomes \""); 4866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, tp->text); 4867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "\" (was \""); 4868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, text); 4869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "\"), "); 4870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->itxt_length != 0) 4874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "iTXt length set, "); 4875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->lang != NULL) 4877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "iTXt language \""); 4879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, tp->lang); 4880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "\", "); 4881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tp->lang_key != NULL) 4884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "iTXt keyword \""); 4886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, tp->lang_key); 4887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "\", "); 4888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pos > ok) 4891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik msg[pos-2] = '\0'; /* Remove the ", " at the end */ 4893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 4894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4897b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4898b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_text_validate(standard_display *dp, png_const_structp pp, 4899b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_infop pi, int check_end) 4900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_textp tp = NULL; 4902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 num_text = png_get_text(pp, pi, &tp, NULL); 4903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (num_text == 2 && tp != NULL) 4905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_check_text(pp, tp, "image name", dp->ps->current->name); 4907b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 4908b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* This exists because prior to 1.5.18 the progressive reader left the 4909b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * png_struct z_stream unreset at the end of the image, so subsequent 4910b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * attempts to use it simply returns Z_STREAM_END. 4911b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 4912b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (check_end) 4913b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari standard_check_text(pp, tp+1, "end marker", "end"); 4914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 4917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[64]; 4919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(msg, "expected two text items, got %lu", 4921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)num_text); 4922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 4923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 4926b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define standard_text_validate(dp,pp,pi,check_end) ((void)0) 4927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 4928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4929b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4930b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_row_validate(standard_display *dp, png_const_structp pp, 4931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int iImage, int iDisplay, png_uint_32 y) 4932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int where; 4934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte std[STANDARD_ROWMAX]; 4935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The row must be pre-initialized to the magic number here for the size 4937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * tests to pass: 4938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(std, 178, sizeof std); 4940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_row(pp, std, dp->id, y); 4941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* At the end both the 'row' and 'display' arrays should end up identical. 4943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * In earlier passes 'row' will be partially filled in, with only the pixels 4944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * that have been read so far, but 'display' will have those pixels 4945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * replicated to fill the unread pixels while reading an interlaced image. 4946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if PNG_LIBPNG_VER < 10506 4947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The side effect inside the libpng sequential reader is that the 'row' 4948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * array retains the correct values for unwritten pixels within the row 4949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bytes, while the 'display' array gets bits off the end of the image (in 4950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the last byte) trashed. Unfortunately in the progressive reader the 4951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * row bytes are always trashed, so we always do a pixel_cmp here even though 4952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * a memcmp of all cbRow bytes will succeed for the sequential reader. 4953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 4954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (iImage >= 0 && 4956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (where = pixel_cmp(std, store_image_row(dp->ps, pp, iImage, y), 4957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->bit_width)) != 0) 4958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[64]; 4960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(msg, "PNG image row[%lu][%d] changed from %.2x to %.2x", 4961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)y, where-1, std[where-1], 4962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_row(dp->ps, pp, iImage, y)[where-1]); 4963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 4964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if PNG_LIBPNG_VER < 10506 4967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* In this case use pixel_cmp because we need to compare a partial 4968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * byte at the end of the row if the row is not an exact multiple 4969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of 8 bits wide. (This is fixed in libpng-1.5.6 and pixel_cmp is 4970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * changed to match!) 4971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 4972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 4973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (iDisplay >= 0 && 4974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (where = pixel_cmp(std, store_image_row(dp->ps, pp, iDisplay, y), 4975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->bit_width)) != 0) 4976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 4977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[64]; 4978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(msg, "display row[%lu][%d] changed from %.2x to %.2x", 4979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)y, where-1, std[where-1], 4980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_row(dp->ps, pp, iDisplay, y)[where-1]); 4981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 4982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 4983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 4984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4985b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 4986b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_image_validate(standard_display *dp, png_const_structp pp, int iImage, 4987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int iDisplay) 4988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 4989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 4990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (iImage >= 0) 4992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_check(dp->ps, pp, iImage); 4993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (iDisplay >= 0) 4995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_check(dp->ps, pp, iDisplay); 4996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 4997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<dp->h; ++y) 4998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_row_validate(dp, pp, iImage, iDisplay, y); 4999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This avoids false positives if the validation code is never called! */ 5001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->ps->validated = 1; 5002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5004b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 5005b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_end(png_structp ppIn, png_infop pi) 5006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 5008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display *dp = voidcast(standard_display*, 5009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_get_progressive_ptr(pp)); 5010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(pi) 5012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Validate the image - progressive reading only produces one variant for 5014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * interlaced images. 5015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5016b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari standard_text_validate(dp, pp, pi, 5017b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari PNG_LIBPNG_VER >= 10518/*check_end: see comments above*/); 5018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_image_validate(dp, pp, 0, -1); 5019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A single test run checking the standard image to ensure it is not damaged. */ 5022b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5023b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstandard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id, 5024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_interlace, int use_update_info) 5025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display d; 5027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik context(psIn, fault); 5028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set up the display (stack frame) variables from the arguments to the 5030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * function and initialize the locals that are filled in later. 5031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display_init(&d, psIn, id, do_interlace, use_update_info); 5033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Everything is protected by a Try/Catch. The functions called also 5035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * typically have local Try/Catch blocks. 5036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 5038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pp; 5040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi; 5041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Get a png_struct for reading the image. This will throw an error if it 5043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * fails, so we don't need to check the result. 5044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp = set_store_for_read(d.ps, &pi, d.id, 5046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.do_interlace ? (d.ps->progressive ? 5047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "pngvalid progressive deinterlacer" : 5048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "pngvalid sequential deinterlacer") : (d.ps->progressive ? 5049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "progressive reader" : "sequential reader")); 5050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Initialize the palette correctly from the png_store_file. */ 5052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_palette_init(&d); 5053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Introduce the correct read function. */ 5055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.ps->progressive) 5056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_progressive_read_fn(pp, &d, standard_info, progressive_row, 5058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_end); 5059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now feed data into the reader until we reach the end: */ 5061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_progressive_read(d.ps, pp, pi); 5062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Note that this takes the store, not the display. */ 5066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_read_fn(pp, d.ps, store_read); 5067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the header values: */ 5069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_info(pp, pi); 5070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The code tests both versions of the images that the sequential 5072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * reader can produce. 5073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_imp(&d, pp, pi, 2 /*images*/); 5075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Need the total bytes in the image below; we can't get to this point 5077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * unless the PNG file values have been checked against the expected 5078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * values. 5079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sequential_row(&d, pp, pi, 0, 1); 5082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* After the last pass loop over the rows again to check that the 5084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * image is correct. 5085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!d.speed) 5087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5088b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari standard_text_validate(&d, pp, pi, 1/*check_end*/); 5089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_image_validate(&d, pp, 0, 1); 5090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.ps->validated = 1; 5093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for validation. */ 5097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!d.ps->validated) 5098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "image read failed silently"); 5099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Successful completion. */ 5101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch(fault) 5104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.ps = fault; /* make sure this hasn't been clobbered. */ 5105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* In either case clean up the store. */ 5107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_read_reset(d.ps); 5108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5110b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 5111b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktest_standard(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type, 5112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int bdlo, int PNG_CONST bdhi) 5113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; bdlo <= bdhi; ++bdlo) 5115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int interlace_type; 5117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (interlace_type = PNG_INTERLACE_NONE; 5119b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari interlace_type < INTERLACE_LAST; ++interlace_type) 5120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, 5122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik interlace_type, 0, 0, 0), 0/*do_interlace*/, pm->use_update_info); 5123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 5125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 5126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; /* keep going */ 5130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5132b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5133b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_standard_test(png_modifier *pm) 5134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Test each colour type over the valid range of bit depths (expressed as 5136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * log2(bit_depth) in turn, stop as soon as any error is detected. 5137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_standard(pm, 0, 0, READ_BDHI)) 5139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_standard(pm, 2, 3, READ_BDHI)) 5142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_standard(pm, 3, 0, 3)) 5145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_standard(pm, 4, 3, READ_BDHI)) 5148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_standard(pm, 6, 3, READ_BDHI)) 5151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/********************************** SIZE TESTS ********************************/ 5156b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 5157b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktest_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type, 5158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int bdlo, int PNG_CONST bdhi) 5159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Run the tests on each combination. 5161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 5162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * NOTE: on my 32 bit x86 each of the following blocks takes 5163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * a total of 3.5 seconds if done across every combo of bit depth 5164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * width and height. This is a waste of time in practice, hence the 5165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * hinc and winc stuff: 5166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static PNG_CONST png_byte hinc[] = {1, 3, 11, 1, 5}; 5168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static PNG_CONST png_byte winc[] = {1, 9, 5, 7, 1}; 5169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (; bdlo <= bdhi; ++bdlo) 5170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 h, w; 5172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (h=1; h<=16; h+=hinc[bdlo]) for (w=1; w<=16; w+=winc[bdlo]) 5174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* First test all the 'size' images against the sequential 5176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * reader using libpng to deinterlace (where required.) This 5177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * validates the write side of libpng. There are four possibilities 5178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to validate. 5179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, 5181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_INTERLACE_NONE, w, h, 0), 0/*do_interlace*/, 5182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 5183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 5185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 5186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, 5188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_INTERLACE_NONE, w, h, 1), 0/*do_interlace*/, 5189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 5190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 5192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 5193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5194b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_WRITE_INTERLACING_SUPPORTED 5195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, 5196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/, 5197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 5198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 5200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 5201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, 5203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/, 5204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 5205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 5207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 5208b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 5209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now validate the interlaced read side - do_interlace true, 5211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in the progressive case this does actually make a difference 5212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to the code used in the non-interlaced case too. 5213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, 5215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/, 5216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 5217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 5219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 5220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5221b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_WRITE_INTERLACING_SUPPORTED 5222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/, 5223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/, 5224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 5225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 5227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 5228b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 5229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; /* keep going */ 5233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5235b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5236b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_size_test(png_modifier *pm) 5237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Test each colour type over the valid range of bit depths (expressed as 5239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * log2(bit_depth) in turn, stop as soon as any error is detected. 5240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_size(pm, 0, 0, READ_BDHI)) 5242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_size(pm, 2, 3, READ_BDHI)) 5245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For the moment don't do the palette test - it's a waste of time when 5248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * compared to the grayscale test. 5249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if 0 5251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_size(pm, 3, 0, 3)) 5252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 5254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_size(pm, 4, 3, READ_BDHI)) 5256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!test_size(pm, 6, 3, READ_BDHI)) 5259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 5260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/******************************* TRANSFORM TESTS ******************************/ 5264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_TRANSFORMS_SUPPORTED 5265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A set of tests to validate libpng image transforms. The possibilities here 5266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * are legion because the transforms can be combined in a combinatorial 5267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * fashion. To deal with this some measure of restraint is required, otherwise 5268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the tests would take forever. 5269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5270b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct image_pixel 5271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* A local (pngvalid) representation of a PNG pixel, in all its 5273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * various forms. 5274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int red, green, blue, alpha; /* For non-palette images. */ 5276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int palette_index; /* For a palette image. */ 5277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type; /* As in the spec. */ 5278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth; /* Defines bit size in row */ 5279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte sample_depth; /* Scale of samples */ 5280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int have_tRNS; /* tRNS chunk may need processing */ 5281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For checking the code calculates double precision floating point values 5283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * along with an error value, accumulated from the transforms. Because an 5284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * sBIT setting allows larger error bounds (indeed, by the spec, apparently 5285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * up to just less than +/-1 in the scaled value) the *lowest* sBIT for each 5286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * channel is stored. This sBIT value is folded in to the stored error value 5287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * at the end of the application of the transforms to the pixel. 5288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double redf, greenf, bluef, alphaf; 5290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double rede, greene, bluee, alphae; 5291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte red_sBIT, green_sBIT, blue_sBIT, alpha_sBIT; 5292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} image_pixel; 5293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Shared utility function, see below. */ 5295b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5296b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_pixel_setf(image_pixel *this, unsigned int max) 5297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->redf = this->red / (double)max; 5299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->greenf = this->green / (double)max; 5300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->bluef = this->blue / (double)max; 5301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphaf = this->alpha / (double)max; 5302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->red < max) 5304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->rede = this->redf * DBL_EPSILON; 5305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->rede = 0; 5307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->green < max) 5308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->greene = this->greenf * DBL_EPSILON; 5309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->greene = 0; 5311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->blue < max) 5312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->bluee = this->bluef * DBL_EPSILON; 5313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->bluee = 0; 5315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->alpha < max) 5316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphae = this->alphaf * DBL_EPSILON; 5317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphae = 0; 5319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Initialize the structure for the next pixel - call this before doing any 5322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transforms and call it for each pixel since all the fields may need to be 5323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * reset. 5324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5325b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5326b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type, 5327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth, png_uint_32 x, store_palette palette) 5328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte sample_depth = (png_byte)(colour_type == 5330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_COLOR_TYPE_PALETTE ? 8 : bit_depth); 5331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int max = (1U<<sample_depth)-1; 5332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Initially just set everything to the same number and the alpha to opaque. 5334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Note that this currently assumes a simple palette where entry x has colour 5335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * rgb(x,x,x)! 5336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->palette_index = this->red = this->green = this->blue = 5338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(row, colour_type, bit_depth, x, 0); 5339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alpha = max; 5340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->red_sBIT = this->green_sBIT = this->blue_sBIT = this->alpha_sBIT = 5341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample_depth; 5342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Then override as appropriate: */ 5344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type == 3) /* palette */ 5345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This permits the caller to default to the sample value. */ 5347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (palette != 0) 5348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int i = this->palette_index; 5350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->red = palette[i].red; 5352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->green = palette[i].green; 5353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->blue = palette[i].blue; 5354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alpha = palette[i].alpha; 5355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* not palette */ 5359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int i = 0; 5361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type & 2) 5363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->green = sample(row, colour_type, bit_depth, x, 1); 5365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->blue = sample(row, colour_type, bit_depth, x, 2); 5366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik i = 2; 5367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type & 4) 5369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alpha = sample(row, colour_type, bit_depth, x, ++i); 5370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Calculate the scaled values, these are simply the values divided by 5373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'max' and the error is initialized to the double precision epsilon value 5374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * from the header file. 5375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_setf(this, max); 5377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Store the input information for use in the transforms - these will 5379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * modify the information. 5380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->colour_type = colour_type; 5382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->bit_depth = bit_depth; 5383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->sample_depth = sample_depth; 5384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->have_tRNS = 0; 5385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Convert a palette image to an rgb image. This necessarily converts the tRNS 5388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * chunk at the same time, because the tRNS will be in palette form. The way 5389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * palette validation works means that the original palette is never updated, 5390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * instead the image_pixel value from the row contains the RGB of the 5391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * corresponding palette entry and *this* is updated. Consequently this routine 5392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * only needs to change the colour type information. 5393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5394b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5395b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_pixel_convert_PLTE(image_pixel *this) 5396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->colour_type == PNG_COLOR_TYPE_PALETTE) 5398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->have_tRNS) 5400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; 5402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->have_tRNS = 0; 5403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->colour_type = PNG_COLOR_TYPE_RGB; 5406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The bit depth of the row changes at this point too (notice that this is 5408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the row format, not the sample depth, which is separate.) 5409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->bit_depth = 8; 5411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Add an alpha channel; this will import the tRNS information because tRNS is 5415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * not valid in an alpha image. The bit depth will invariably be set to at 5416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * least 8. Palette images will be converted to alpha (using the above API). 5417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5418b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5419b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_pixel_add_alpha(image_pixel *this, PNG_CONST standard_display *display) 5420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->colour_type == PNG_COLOR_TYPE_PALETTE) 5422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_convert_PLTE(this); 5423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((this->colour_type & PNG_COLOR_MASK_ALPHA) == 0) 5425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->colour_type == PNG_COLOR_TYPE_GRAY) 5427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->bit_depth < 8) 5429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->bit_depth = 8; 5430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->have_tRNS) 5432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->have_tRNS = 0; 5434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the input, original, channel value here against the 5436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * original tRNS gray chunk valie. 5437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->red == display->transparent.red) 5439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphaf = 0; 5440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphaf = 1; 5442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphaf = 1; 5445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; 5447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (this->colour_type == PNG_COLOR_TYPE_RGB) 5450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->have_tRNS) 5452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->have_tRNS = 0; 5454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Again, check the exact input values, not the current transformed 5456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value! 5457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (this->red == display->transparent.red && 5459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->green == display->transparent.green && 5460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->blue == display->transparent.blue) 5461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphaf = 0; 5462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphaf = 1; 5464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; 5466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The error in the alpha is zero and the sBIT value comes from the 5470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * original sBIT data (actually it will always be the original bit depth). 5471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alphae = 0; 5473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->alpha_sBIT = display->alpha_sBIT; 5474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5477b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstruct transform_display; 5478b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct image_transform 5479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The name of this transform: a string. */ 5481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *name; 5482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Each transform can be disabled from the command line: */ 5484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int enable; 5485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The global list of transforms; read only. */ 5487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct image_transform *PNG_CONST list; 5488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The global count of the number of times this transform has been set on an 5490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * image. 5491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int global_use; 5493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The local count of the number of times this transform has been set. */ 5495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int local_use; 5496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The next transform in the list, each transform must call its own next 5498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transform after it has processed the pixel successfully. 5499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST struct image_transform *next; 5501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* A single transform for the image, expressed as a series of function 5503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * callbacks and some space for values. 5504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 5505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * First a callback to add any required modifications to the png_modifier; 5506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this gets called just before the modifier is set up for read. 5507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik void (*ini)(PNG_CONST struct image_transform *this, 5509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct transform_display *that); 5510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And a callback to set the transform on the current png_read_struct: 5512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik void (*set)(PNG_CONST struct image_transform *this, 5514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct transform_display *that, png_structp pp, png_infop pi); 5515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Then a transform that takes an input pixel in one PNG format or another 5517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * and modifies it by a pngvalid implementation of the transform (thus 5518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * duplicating the libpng intent without, we hope, duplicating the bugs 5519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in the libpng implementation!) The png_structp is solely to allow error 5520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * reporting via png_error and png_warning. 5521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik void (*mod)(PNG_CONST struct image_transform *this, image_pixel *that, 5523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp, PNG_CONST struct transform_display *display); 5524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Add this transform to the list and return true if the transform is 5526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * meaningful for this colour type and bit depth - if false then the 5527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transform should have no effect on the image so there's not a lot of 5528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * point running it. 5529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int (*add)(struct image_transform *this, 5531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST struct image_transform **that, png_byte colour_type, 5532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth); 5533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} image_transform; 5534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5535b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct transform_display 5536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display this; 5538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Parameters */ 5540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modifier* pm; 5541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform* transform_list; 5542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Local variables */ 5544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte output_colour_type; 5545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte output_bit_depth; 5546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Modifications (not necessarily used.) */ 5548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gama_modification gama_mod; 5549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik chrm_modification chrm_mod; 5550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik srgb_modification srgb_mod; 5551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} transform_display; 5552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Set sRGB, cHRM and gAMA transforms as required by the current encoding. */ 5554b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5555b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_set_encoding(transform_display *this) 5556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set up the png_modifier '_current' fields then use these to determine how 5558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to add appropriate chunks. 5559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modifier *pm = this->pm; 5561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_set_encoding(pm); 5563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (modifier_color_encoding_is_set(pm)) 5565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (modifier_color_encoding_is_sRGB(pm)) 5567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik srgb_modification_init(&this->srgb_mod, pm, PNG_sRGB_INTENT_ABSOLUTE); 5568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set gAMA and cHRM separately. */ 5572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gama_modification_init(&this->gama_mod, pm, pm->current_gamma); 5573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->current_encoding != 0) 5575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik chrm_modification_init(&this->chrm_mod, pm, pm->current_encoding); 5576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Three functions to end the list: */ 5581b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5582b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_ini_end(PNG_CONST image_transform *this, 5583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that) 5584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(this) 5586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(that) 5587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5589b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5590b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_set_end(PNG_CONST image_transform *this, 5591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 5592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(this) 5594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(that) 5595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(pp) 5596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(pi) 5597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* At the end of the list recalculate the output image pixel value from the 5600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * double precision values set up by the preceding 'mod' calls: 5601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5602b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic unsigned int 5603b50c217251b086440efcdb273c22f86a06c80cbaChris Craiksample_scale(double sample_value, unsigned int scale) 5604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample_value = floor(sample_value * scale + .5); 5606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Return NaN as 0: */ 5608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!(sample_value > 0)) 5609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample_value = 0; 5610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (sample_value > scale) 5611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample_value = scale; 5612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (unsigned int)sample_value; 5614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5616b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5617b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_mod_end(PNG_CONST image_transform *this, image_pixel *that, 5618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp, PNG_CONST transform_display *display) 5619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int scale = (1U<<that->sample_depth)-1; 5621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(this) 5623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(pp) 5624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(display) 5625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* At the end recalculate the digitized red green and blue values according 5627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to the current sample_depth of the pixel. 5628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 5629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The sample value is simply scaled to the maximum, checking for over 5630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * and underflow (which can both happen for some image transforms, 5631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * including simple size scaling, though libpng doesn't do that at present. 5632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->red = sample_scale(that->redf, scale); 5634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The error value is increased, at the end, according to the lowest sBIT 5636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value seen. Common sense tells us that the intermediate integer 5637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * representations are no more accurate than +/- 0.5 in the integral values, 5638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the sBIT allows the implementation to be worse than this. In addition the 5639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG specification actually permits any error within the range (-1..+1), 5640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * but that is ignored here. Instead the final digitized value is compared, 5641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * below to the digitized value of the error limits - this has the net effect 5642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of allowing (almost) +/-1 in the output value. It's difficult to see how 5643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * any algorithm that digitizes intermediate results can be more accurate. 5644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->rede += 1./(2*((1U<<that->red_sBIT)-1)); 5646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type & PNG_COLOR_MASK_COLOR) 5648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->green = sample_scale(that->greenf, scale); 5650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->blue = sample_scale(that->bluef, scale); 5651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->greene += 1./(2*((1U<<that->green_sBIT)-1)); 5652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluee += 1./(2*((1U<<that->blue_sBIT)-1)); 5653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->blue = that->green = that->red; 5657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluef = that->greenf = that->redf; 5658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluee = that->greene = that->rede; 5659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((that->colour_type & PNG_COLOR_MASK_ALPHA) || 5662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type == PNG_COLOR_TYPE_PALETTE) 5663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alpha = sample_scale(that->alphaf, scale); 5665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alphae += 1./(2*((1U<<that->alpha_sBIT)-1)); 5666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alpha = scale; /* opaque */ 5670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alpha = 1; /* Override this. */ 5671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alphae = 0; /* It's exact ;-) */ 5672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Static 'end' structure: */ 5676b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic image_transform image_transform_end = 5677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "(end)", /* name */ 5679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1, /* enable */ 5680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0, /* list */ 5681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0, /* global_use */ 5682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0, /* local_use */ 5683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0, /* next */ 5684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_ini_end, 5685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_set_end, 5686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_mod_end, 5687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0 /* never called, I want it to crash if it is! */ 5688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}; 5689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Reader callbacks and implementations, where they differ from the standard 5691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * ones. 5692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5693b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5694b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_display_init(transform_display *dp, png_modifier *pm, png_uint_32 id, 5695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform *transform_list) 5696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(dp, 0, sizeof *dp); 5698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Standard fields */ 5700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/, 5701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 5702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Parameter fields */ 5704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pm = pm; 5705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transform_list = transform_list; 5706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Local variable fields */ 5708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->output_colour_type = 255; /* invalid */ 5709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->output_bit_depth = 255; /* invalid */ 5710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5712b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5713b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_info_imp(transform_display *dp, png_structp pp, png_infop pi) 5714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Reuse the standard stuff as appropriate. */ 5716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_part1(&dp->this, pp, pi); 5717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now set the list of transforms. */ 5719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transform_list->set(dp->transform_list, dp, pp, pi); 5720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Update the info structure for these transforms: */ 5722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i = dp->this.use_update_info; 5724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Always do one call, even if use_update_info is 0. */ 5725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik do 5726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_update_info(pp, pi); 5727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (--i > 0); 5728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And get the output information into the standard_display */ 5731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_part2(&dp->this, pp, pi, 1/*images*/); 5732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Plus the extra stuff we need for the transform tests: */ 5734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->output_colour_type = png_get_color_type(pp, pi); 5735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->output_bit_depth = png_get_bit_depth(pp, pi); 5736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Validate the combination of colour type and bit depth that we are getting 5738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * out of libpng; the semantics of something not in the PNG spec are, at 5739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * best, unclear. 5740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (dp->output_colour_type) 5742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_COLOR_TYPE_PALETTE: 5744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->output_bit_depth > 8) goto error; 5745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /*FALL THROUGH*/ 5746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_COLOR_TYPE_GRAY: 5747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->output_bit_depth == 1 || dp->output_bit_depth == 2 || 5748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->output_bit_depth == 4) 5749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 5750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /*FALL THROUGH*/ 5751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 5752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->output_bit_depth == 8 || dp->output_bit_depth == 16) 5753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 5754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /*FALL THROUGH*/ 5755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik error: 5756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char message[128]; 5758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos; 5759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, 0, 5761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "invalid final bit depth: colour type("); 5762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, dp->output_colour_type); 5763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, ") with bit depth: "); 5764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); 5765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, message); 5767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use a test pixel to check that the output agrees with what we expect - 5771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this avoids running the whole test if the output is unexpected. 5772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel test_pixel; 5775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(&test_pixel, 0, sizeof test_pixel); 5777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_pixel.colour_type = dp->this.colour_type; /* input */ 5778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_pixel.bit_depth = dp->this.bit_depth; 5779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE) 5780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_pixel.sample_depth = 8; 5781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_pixel.sample_depth = test_pixel.bit_depth; 5783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Don't need sBIT here, but it must be set to non-zero to avoid 5784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * arithmetic overflows. 5785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_pixel.have_tRNS = dp->this.is_transparent; 5787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_pixel.red_sBIT = test_pixel.green_sBIT = test_pixel.blue_sBIT = 5788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_pixel.alpha_sBIT = test_pixel.sample_depth; 5789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transform_list->mod(dp->transform_list, &test_pixel, pp, dp); 5791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (test_pixel.colour_type != dp->output_colour_type) 5793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char message[128]; 5795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = safecat(message, sizeof message, 0, "colour type "); 5796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, dp->output_colour_type); 5798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, " expected "); 5799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, test_pixel.colour_type); 5800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, message); 5802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (test_pixel.bit_depth != dp->output_bit_depth) 5805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char message[128]; 5807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = safecat(message, sizeof message, 0, "bit depth "); 5808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); 5810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, " expected "); 5811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, test_pixel.bit_depth); 5812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, message); 5814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If both bit depth and colour type are correct check the sample depth. 5817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * I believe these are both internal errors. 5818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (test_pixel.colour_type == PNG_COLOR_TYPE_PALETTE) 5820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (test_pixel.sample_depth != 8) /* oops - internal error! */ 5822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "pngvalid: internal: palette sample depth not 8"); 5823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (test_pixel.sample_depth != dp->output_bit_depth) 5825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char message[128]; 5827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = safecat(message, sizeof message, 0, 5828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "internal: sample depth "); 5829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, dp->output_bit_depth); 5831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, " expected "); 5832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, test_pixel.sample_depth); 5833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, message); 5835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5839b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 5840b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_info(png_structp pp, png_infop pi) 5841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_info_imp(voidcast(transform_display*, png_get_progressive_ptr(pp)), 5843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp, pi); 5844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5846b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5847b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_range_check(png_const_structp pp, unsigned int r, unsigned int g, 5848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int b, unsigned int a, unsigned int in_digitized, double in, 5849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int out, png_byte sample_depth, double err, double limit, 5850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *name, double digitization_error) 5851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Compare the scaled, digitzed, values of our local calculation (in+-err) 5853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * with the digitized values libpng produced; 'sample_depth' is the actual 5854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * digitization depth of the libpng output colors (the bit depth except for 5855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * palette images where it is always 8.) The check on 'err' is to detect 5856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * internal errors in pngvalid itself. 5857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int max = (1U<<sample_depth)-1; 5859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double in_min = ceil((in-err)*max - digitization_error); 5860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double in_max = floor((in+err)*max + digitization_error); 5861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (err > limit || !(out >= in_min && out <= in_max)) 5862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char message[256]; 5864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos; 5865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, 0, name); 5867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, " output value error: rgba("); 5868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, r); 5869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, ","); 5870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, g); 5871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, ","); 5872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, b); 5873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, ","); 5874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, a); 5875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, "): "); 5876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, out); 5877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, " expected: "); 5878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(message, sizeof message, pos, in_digitized); 5879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, " ("); 5880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(message, sizeof message, pos, (in-err)*max, 3); 5881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, ".."); 5882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(message, sizeof message, pos, (in+err)*max, 3); 5883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(message, sizeof message, pos, ")"); 5884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, message); 5886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 5888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5889b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 5890b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_image_validate(transform_display *dp, png_const_structp pp, 5891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi) 5892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 5893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Constants for the loop below: */ 5894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_store* PNG_CONST ps = dp->this.ps; 5895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte in_ct = dp->this.colour_type; 5896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte in_bd = dp->this.bit_depth; 5897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 w = dp->this.w; 5898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 h = dp->this.h; 5899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte out_ct = dp->output_colour_type; 5900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte out_bd = dp->output_bit_depth; 5901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte sample_depth = (png_byte)(out_ct == 5902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_COLOR_TYPE_PALETTE ? 8 : out_bd); 5903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte red_sBIT = dp->this.red_sBIT; 5904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte green_sBIT = dp->this.green_sBIT; 5905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte blue_sBIT = dp->this.blue_sBIT; 5906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte alpha_sBIT = dp->this.alpha_sBIT; 5907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int have_tRNS = dp->this.is_transparent; 5908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double digitization_error; 5909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette out_palette; 5911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 5912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(pi) 5914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for row overwrite errors */ 5916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_check(dp->this.ps, pp, 0); 5917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Read the palette corresponding to the output if the output colour type 5919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * indicates a palette, othewise set out_palette to garbage. 5920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (out_ct == PNG_COLOR_TYPE_PALETTE) 5922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Validate that the palette count itself has not changed - this is not 5924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * expected. 5925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int npalette = (-1); 5927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)read_palette(out_palette, &npalette, pp, pi); 5929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (npalette != dp->this.npalette) 5930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "unexpected change in palette size"); 5931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik digitization_error = .5; 5933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte in_sample_depth; 5937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(out_palette, 0x5e, sizeof out_palette); 5939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5940b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* use-input-precision means assume that if the input has 8 bit (or less) 5941b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * samples and the output has 16 bit samples the calculations will be done 5942b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * with 8 bit precision, not 16. 5943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (in_ct == PNG_COLOR_TYPE_PALETTE || in_bd < 16) 5945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_sample_depth = 8; 5946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_sample_depth = in_bd; 5948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sample_depth != 16 || in_sample_depth > 8 || 5950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik !dp->pm->calculations_use_input_precision) 5951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik digitization_error = .5; 5952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5953b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Else calculations are at 8 bit precision, and the output actually 5954b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * consists of scaled 8-bit values, so scale .5 in 8 bits to the 16 bits: 5955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 5957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik digitization_error = .5 * 257; 5958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 5959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<h; ++y) 5961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_bytep PNG_CONST pRow = store_image_row(ps, pp, 0, y); 5963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 x; 5964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The original, standard, row pre-transforms. */ 5966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte std[STANDARD_ROWMAX]; 5967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_row(pp, std, in_ct, in_bd, y); 5969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Go through each original pixel transforming it and comparing with what 5971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng did to the same pixel. 5972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (x=0; x<w; ++x) 5974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel in_pixel, out_pixel; 5976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int r, g, b, a; 5977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Find out what we think the pixel should be: */ 5979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_init(&in_pixel, std, in_ct, in_bd, x, dp->this.palette); 5980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.red_sBIT = red_sBIT; 5982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.green_sBIT = green_sBIT; 5983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.blue_sBIT = blue_sBIT; 5984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.alpha_sBIT = alpha_sBIT; 5985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.have_tRNS = have_tRNS; 5986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For error detection, below. */ 5988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik r = in_pixel.red; 5989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik g = in_pixel.green; 5990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik b = in_pixel.blue; 5991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik a = in_pixel.alpha; 5992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->transform_list->mod(dp->transform_list, &in_pixel, pp, dp); 5994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 5995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Read the output pixel and compare it to what we got, we don't 5996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * use the error field here, so no need to update sBIT. 5997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 5998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_init(&out_pixel, pRow, out_ct, out_bd, x, out_palette); 5999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* We don't expect changes to the index here even if the bit depth is 6001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * changed. 6002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (in_ct == PNG_COLOR_TYPE_PALETTE && 6004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_ct == PNG_COLOR_TYPE_PALETTE) 6005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (in_pixel.palette_index != out_pixel.palette_index) 6007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "unexpected transformed palette index"); 6008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the colours for palette images too - in fact the palette could 6011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * be separately verified itself in most cases. 6012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (in_pixel.red != out_pixel.red) 6014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_range_check(pp, r, g, b, a, in_pixel.red, in_pixel.redf, 6015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_pixel.red, sample_depth, in_pixel.rede, 6016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pm->limit + 1./(2*((1U<<in_pixel.red_sBIT)-1)), "red/gray", 6017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik digitization_error); 6018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((out_ct & PNG_COLOR_MASK_COLOR) != 0 && 6020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.green != out_pixel.green) 6021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_range_check(pp, r, g, b, a, in_pixel.green, 6022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.greenf, out_pixel.green, sample_depth, in_pixel.greene, 6023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pm->limit + 1./(2*((1U<<in_pixel.green_sBIT)-1)), "green", 6024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik digitization_error); 6025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((out_ct & PNG_COLOR_MASK_COLOR) != 0 && 6027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.blue != out_pixel.blue) 6028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_range_check(pp, r, g, b, a, in_pixel.blue, in_pixel.bluef, 6029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_pixel.blue, sample_depth, in_pixel.bluee, 6030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pm->limit + 1./(2*((1U<<in_pixel.blue_sBIT)-1)), "blue", 6031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik digitization_error); 6032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0 && 6034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.alpha != out_pixel.alpha) 6035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_range_check(pp, r, g, b, a, in_pixel.alpha, 6036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_pixel.alphaf, out_pixel.alpha, sample_depth, in_pixel.alphae, 6037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pm->limit + 1./(2*((1U<<in_pixel.alpha_sBIT)-1)), "alpha", 6038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik digitization_error); 6039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } /* pixel (x) loop */ 6040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } /* row (y) loop */ 6041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Record that something was actually checked to avoid a false positive. */ 6043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->this.ps->validated = 1; 6044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6046b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 6047b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_end(png_structp ppIn, png_infop pi) 6048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 6050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *dp = voidcast(transform_display*, 6051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_get_progressive_ptr(pp)); 6052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!dp->this.speed) 6054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_image_validate(dp, pp, pi); 6055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->this.ps->validated = 1; 6057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A single test run. */ 6060b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6061b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn, 6062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform* transform_listIn, PNG_CONST char * volatile name) 6063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display d; 6065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik context(&pmIn->this, fault); 6066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display_init(&d, pmIn, idIn, transform_listIn); 6068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 6070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 6072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pp; 6073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi; 6074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char full_name[256]; 6075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Make sure the encoding fields are correct and enter the required 6077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * modifications. 6078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_set_encoding(&d); 6080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Add any modifications required by the transform list. */ 6082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.transform_list->ini(d.transform_list, &d); 6083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Add the color space information, if any, to the name. */ 6085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(full_name, sizeof full_name, pos, name); 6086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat_current_encoding(full_name, sizeof full_name, pos, d.pm); 6087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Get a png_struct for reading the image. */ 6089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp = set_modifier_for_read(d.pm, &pi, d.this.id, full_name); 6090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_palette_init(&d.this); 6091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if 0 6093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Logging (debugging only) */ 6094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char buffer[256]; 6096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)store_message(&d.pm->this, pp, buffer, sizeof buffer, 0, 6098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "running test"); 6099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "%s\n", buffer); 6101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 6103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Introduce the correct read function. */ 6105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.pm->this.progressive) 6106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Share the row function with the standard implementation. */ 6108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_progressive_read_fn(pp, &d, transform_info, progressive_row, 6109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_end); 6110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now feed data into the reader until we reach the end: */ 6112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_progressive_read(d.pm, pp, pi); 6113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* modifier_read expects a png_modifier* */ 6117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_read_fn(pp, d.pm, modifier_read); 6118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the header values: */ 6120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_info(pp, pi); 6121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Process the 'info' requirements. Only one image is generated */ 6123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_info_imp(&d, pp, pi); 6124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sequential_row(&d.this, pp, pi, -1, 0); 6126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!d.this.speed) 6128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_image_validate(&d, pp, pi); 6129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.this.ps->validated = 1; 6131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_reset(d.pm); 6134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch(fault) 6137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6138b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari modifier_reset(voidcast(png_modifier*,(void*)fault)); 6139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The transforms: */ 6143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define ITSTRUCT(name) image_transform_##name 6144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define ITDATA(name) image_transform_data_##name 6145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define image_transform_ini image_transform_default_ini 6146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define IT(name)\ 6147b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic image_transform ITSTRUCT(name) =\ 6148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{\ 6149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik #name,\ 6150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 1, /*enable*/\ 6151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik &PT, /*list*/\ 6152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0, /*global_use*/\ 6153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0, /*local_use*/\ 6154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0, /*next*/\ 6155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_ini,\ 6156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_png_set_##name##_set,\ 6157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_png_set_##name##_mod,\ 6158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_png_set_##name##_add\ 6159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(end) /* stores the previous transform */ 6161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* To save code: */ 6163b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6164b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_default_ini(PNG_CONST image_transform *this, 6165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that) 6166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->ini(this->next, that); 6168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_BACKGROUND_SUPPORTED 6171b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6172b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_default_add(image_transform *this, 6173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(colour_type) 6176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(bit_depth) 6177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 6182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 6184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_EXPAND_SUPPORTED 6186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_palette_to_rgb */ 6187b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6188b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_palette_to_rgb_set(PNG_CONST image_transform *this, 6189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_palette_to_rgb(pp); 6192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6195b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6196b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_palette_to_rgb_mod(PNG_CONST image_transform *this, 6197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_PALETTE) 6201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_convert_PLTE(that); 6202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6206b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6207b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_palette_to_rgb_add(image_transform *this, 6208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(bit_depth) 6211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return colour_type == PNG_COLOR_TYPE_PALETTE; 6216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6218b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(palette_to_rgb); 6219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(palette_to_rgb) 6221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_EXPAND_SUPPORTED */ 6222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_EXPAND_SUPPORTED 6224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_tRNS_to_alpha */ 6225b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6226b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_tRNS_to_alpha_set(PNG_CONST image_transform *this, 6227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_tRNS_to_alpha(pp); 6230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6233b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6234b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_tRNS_to_alpha_mod(PNG_CONST image_transform *this, 6235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* LIBPNG BUG: this always forces palette images to RGB. */ 6239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_PALETTE) 6240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_convert_PLTE(that); 6241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This effectively does an 'expand' only if there is some transparency to 6243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * convert to an alpha channel. 6244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->have_tRNS) 6246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_add_alpha(that, &display->this); 6247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* LIBPNG BUG: otherwise libpng still expands to 8 bits! */ 6249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->bit_depth < 8) 6252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bit_depth =8; 6253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->sample_depth < 8) 6254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->sample_depth = 8; 6255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6260b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6261b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_tRNS_to_alpha_add(image_transform *this, 6262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(bit_depth) 6265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* We don't know yet whether there will be a tRNS chunk, but we know that 6270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this transformation should do nothing if there already is an alpha 6271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * channel. 6272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (colour_type & PNG_COLOR_MASK_ALPHA) == 0; 6274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6276b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(tRNS_to_alpha); 6277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(tRNS_to_alpha) 6279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_EXPAND_SUPPORTED */ 6280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED 6282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_gray_to_rgb */ 6283b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6284b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_gray_to_rgb_set(PNG_CONST image_transform *this, 6285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_gray_to_rgb(pp); 6288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6291b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6292b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_gray_to_rgb_mod(PNG_CONST image_transform *this, 6293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* NOTE: we can actually pend the tRNS processing at this point because we 6297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * can correctly recognize the original pixel value even though we have 6298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * mapped the one gray channel to the three RGB ones, but in fact libpng 6299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * doesn't do this, so we don't either. 6300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((that->colour_type & PNG_COLOR_MASK_COLOR) == 0 && that->have_tRNS) 6302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_add_alpha(that, &display->this); 6303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Simply expand the bit depth and alter the colour type as required. */ 6305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_GRAY) 6306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* RGB images have a bit depth at least equal to '8' */ 6308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->bit_depth < 8) 6309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->sample_depth = that->bit_depth = 8; 6310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And just changing the colour type works here because the green and blue 6312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * channels are being maintained in lock-step with the red/gray: 6313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_RGB; 6315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) 6318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_RGB_ALPHA; 6319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6323b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6324b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_gray_to_rgb_add(image_transform *this, 6325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(bit_depth) 6328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (colour_type & PNG_COLOR_MASK_COLOR) == 0; 6333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6335b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(gray_to_rgb); 6336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(gray_to_rgb) 6338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */ 6339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_EXPAND_SUPPORTED 6341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_expand */ 6342b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6343b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_set(PNG_CONST image_transform *this, 6344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_expand(pp); 6347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6350b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6351b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_mod(PNG_CONST image_transform *this, 6352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The general expand case depends on what the colour type is: */ 6356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_PALETTE) 6357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_convert_PLTE(that); 6358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (that->bit_depth < 8) /* grayscale */ 6359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->sample_depth = that->bit_depth = 8; 6360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->have_tRNS) 6362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_add_alpha(that, &display->this); 6363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6367b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6368b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_add(image_transform *this, 6369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(bit_depth) 6372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 'expand' should do nothing for RGBA or GA input - no tRNS and the bit 6377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * depth is at least 8 already. 6378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (colour_type & PNG_COLOR_MASK_ALPHA) == 0; 6380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6382b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(expand); 6383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(expand) 6385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_EXPAND_SUPPORTED */ 6386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_EXPAND_SUPPORTED 6388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_expand_gray_1_2_4_to_8 6389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * LIBPNG BUG: this just does an 'expand' 6390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6391b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6392b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_gray_1_2_4_to_8_set( 6393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform *this, transform_display *that, png_structp pp, 6394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi) 6395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_expand_gray_1_2_4_to_8(pp); 6397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6400b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6401b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_gray_1_2_4_to_8_mod( 6402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform *this, image_pixel *that, png_const_structp pp, 6403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_png_set_expand_mod(this, that, pp, display); 6406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6408b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6409b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this, 6410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return image_transform_png_set_expand_add(this, that, colour_type, 6413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_depth); 6414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6416b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(expand_gray_1_2_4_to_8); 6417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(expand_gray_1_2_4_to_8) 6419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_EXPAND_SUPPORTED */ 6420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_EXPAND_16_SUPPORTED 6422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_expand_16 */ 6423b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6424b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_16_set(PNG_CONST image_transform *this, 6425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_expand_16(pp); 6428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6431b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6432b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_16_mod(PNG_CONST image_transform *this, 6433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Expect expand_16 to expand everything to 16 bits as a result of also 6437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * causing 'expand' to happen. 6438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_PALETTE) 6440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_convert_PLTE(that); 6441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->have_tRNS) 6443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_add_alpha(that, &display->this); 6444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->bit_depth < 16) 6446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->sample_depth = that->bit_depth = 16; 6447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6451b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6452b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_expand_16_add(image_transform *this, 6453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(colour_type) 6456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* expand_16 does something unless the bit depth is already 16. */ 6461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return bit_depth < 16; 6462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6464b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(expand_16); 6465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(expand_16) 6467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_EXPAND_16_SUPPORTED */ 6468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* API added in 1.5.4 */ 6470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_scale_16 */ 6471b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6472b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_scale_16_set(PNG_CONST image_transform *this, 6473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_scale_16(pp); 6476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6479b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6480b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_scale_16_mod(PNG_CONST image_transform *this, 6481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->bit_depth == 16) 6485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->sample_depth = that->bit_depth = 8; 6487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->red_sBIT > 8) that->red_sBIT = 8; 6488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->green_sBIT > 8) that->green_sBIT = 8; 6489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->blue_sBIT > 8) that->blue_sBIT = 8; 6490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->alpha_sBIT > 8) that->alpha_sBIT = 8; 6491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6496b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6497b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_scale_16_add(image_transform *this, 6498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(colour_type) 6501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return bit_depth > 8; 6506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6508b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(scale_16); 6509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(scale_16) 6511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SCALE_16_TO_8_SUPPORTED (1.5.4 on) */ 6512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_16_TO_8_SUPPORTED /* the default before 1.5.4 */ 6514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_strip_16 */ 6515b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6516b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_strip_16_set(PNG_CONST image_transform *this, 6517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_strip_16(pp); 6520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6523b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6524b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_strip_16_mod(PNG_CONST image_transform *this, 6525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->bit_depth == 16) 6529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->sample_depth = that->bit_depth = 8; 6531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->red_sBIT > 8) that->red_sBIT = 8; 6532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->green_sBIT > 8) that->green_sBIT = 8; 6533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->blue_sBIT > 8) that->blue_sBIT = 8; 6534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->alpha_sBIT > 8) that->alpha_sBIT = 8; 6535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Prior to 1.5.4 png_set_strip_16 would use an 'accurate' method if this 6537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * configuration option is set. From 1.5.4 the flag is never set and the 6538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'scale' API (above) must be used. 6539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_ACCURATE_SCALE_SUPPORTED 6541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if PNG_LIBPNG_VER >= 10504 6542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# error PNG_READ_ACCURATE_SCALE should not be set 6543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 6544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The strip 16 algorithm drops the low 8 bits rather than calculating 6546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 1/257, so we need to adjust the permitted errors appropriately: 6547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Notice that this is only relevant prior to the addition of the 6548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!) 6549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double d = (255-128.5)/65535; 6552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->rede += d; 6553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->greene += d; 6554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluee += d; 6555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alphae += d; 6556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 6558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6563b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6564b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_strip_16_add(image_transform *this, 6565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(colour_type) 6568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return bit_depth > 8; 6573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6575b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(strip_16); 6576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(strip_16) 6578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_16_TO_8_SUPPORTED */ 6579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED 6581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_strip_alpha */ 6582b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6583b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_strip_alpha_set(PNG_CONST image_transform *this, 6584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_strip_alpha(pp); 6587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6590b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6591b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_strip_alpha_mod(PNG_CONST image_transform *this, 6592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) 6596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_GRAY; 6597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) 6598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_RGB; 6599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->have_tRNS = 0; 6601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alphaf = 1; 6602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 6604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6606b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 6607b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_strip_alpha_add(image_transform *this, 6608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 6609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(bit_depth) 6611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 6613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 6614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (colour_type & PNG_COLOR_MASK_ALPHA) != 0; 6616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6618b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(strip_alpha); 6619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 6620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(strip_alpha) 6621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */ 6622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED 6624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_rgb_to_gray(png_structp, int err_action, double red, double green) 6625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_set_rgb_to_gray_fixed(png_structp, int err_action, png_fixed_point red, 6626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_fixed_point green) 6627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_get_rgb_to_gray_status 6628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 6629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The 'default' test here uses values known to be used inside libpng: 6630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 6631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * red: 6968 6632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * green: 23434 6633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * blue: 2366 6634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 6635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * These values are being retained for compatibility, along with the somewhat 6636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * broken truncation calculation in the fast-and-inaccurate code path. Older 6637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * versions of libpng will fail the accuracy tests below because they use the 6638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * truncation algorithm everywhere. 6639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define data ITDATA(rgb_to_gray) 6641b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic struct 6642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double gamma; /* File gamma to use in processing */ 6644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following are the parameters for png_set_rgb_to_gray: */ 6646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 6647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double red_to_set; 6648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double green_to_set; 6649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 6650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_fixed_point red_to_set; 6651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_fixed_point green_to_set; 6652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 6653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The actual coefficients: */ 6655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double red_coefficient; 6656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double green_coefficient; 6657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double blue_coefficient; 6658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set if the coeefficients have been overridden. */ 6660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int coefficients_overridden; 6661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} data; 6662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef image_transform_ini 6664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define image_transform_ini image_transform_png_set_rgb_to_gray_ini 6665b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6666b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_rgb_to_gray_ini(PNG_CONST image_transform *this, 6667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that) 6668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modifier *pm = that->pm; 6670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST color_encoding *e = pm->current_encoding; 6671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(this) 6673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Since we check the encoding this flag must be set: */ 6675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_uses_encoding = 1; 6676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If 'e' is not NULL chromaticity information is present and either a cHRM 6678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * or an sRGB chunk will be inserted. 6679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (e != 0) 6681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Coefficients come from the encoding, but may need to be normalized to a 6683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * white point Y of 1.0 6684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double whiteY = e->red.Y + e->green.Y + e->blue.Y; 6686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.red_coefficient = e->red.Y; 6688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_coefficient = e->green.Y; 6689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.blue_coefficient = e->blue.Y; 6690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (whiteY != 1) 6692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.red_coefficient /= whiteY; 6694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_coefficient /= whiteY; 6695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.blue_coefficient /= whiteY; 6696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The default (built in) coeffcients, as above: */ 6702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.red_coefficient = 6968 / 32768.; 6703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_coefficient = 23434 / 32768.; 6704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.blue_coefficient = 2366 / 32768.; 6705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.gamma = pm->current_gamma; 6708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If not set then the calculations assume linear encoding (implicitly): */ 6710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (data.gamma == 0) 6711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.gamma = 1; 6712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The arguments to png_set_rgb_to_gray can override the coefficients implied 6714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * by the color space encoding. If doing exhaustive checks do the override 6715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in each case, otherwise do it randomly. 6716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_exhaustive) 6718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* First time in coefficients_overridden is 0, the following sets it to 1, 6720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * so repeat if it is set. If a test fails this may mean we subsequently 6721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * skip a non-override test, ignore that. 6722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.coefficients_overridden = !data.coefficients_overridden; 6724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->repeat = data.coefficients_overridden != 0; 6725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.coefficients_overridden = random_choice(); 6729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (data.coefficients_overridden) 6731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* These values override the color encoding defaults, simply use random 6733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * numbers. 6734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 ru; 6736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double total; 6737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik RANDOMIZE(ru); 6739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_coefficient = total = (ru & 0xffff) / 65535.; 6740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ru >>= 16; 6741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.red_coefficient = (1 - total) * (ru & 0xffff) / 65535.; 6742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik total += data.red_coefficient; 6743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.blue_coefficient = 1 - total; 6744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 6746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.red_to_set = data.red_coefficient; 6747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_to_set = data.green_coefficient; 6748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 6749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.red_to_set = fix(data.red_coefficient); 6750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_to_set = fix(data.green_coefficient); 6751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 6752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following just changes the error messages: */ 6754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->encoding_ignored = 1; 6755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.red_to_set = -1; 6760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_to_set = -1; 6761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Adjust the error limit in the png_modifier because of the larger errors 6764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * produced in the digitization during the gamma handling. 6765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (data.gamma != 1) /* Use gamma tables */ 6767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->this.bit_depth == 16 || pm->assume_16_bit_calculations) 6769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6770b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* The computations have the form: 6771b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 6772b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * r * rc + g * gc + b * bc 6773b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 6774b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Each component of which is +/-1/65535 from the gamma_to_1 table 6775b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * lookup, resulting in a base error of +/-6. The gamma_from_1 6776b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * conversion adds another +/-2 in the 16-bit case and 6777b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * +/-(1<<(15-PNG_MAX_GAMMA_8)) in the 8-bit case. 6778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6779b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari that->pm->limit += pow( 6780b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# if PNG_MAX_GAMMA_8 < 14 6781b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari (that->this.bit_depth == 16 ? 8. : 6782b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 6. + (1<<(15-PNG_MAX_GAMMA_8))) 6783b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# else 6784b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 8. 6785b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 6786b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /65535, data.gamma); 6787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Rounding to 8 bits in the linear space causes massive errors which 6792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * will trigger the error check in transform_range_check. Fix that 6793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * here by taking the gamma encoding into account. 6794b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 6795b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * When DIGITIZE is set because a pre-1.7 version of libpng is being 6796b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * tested allow a bigger slack. 6797b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 6798b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * NOTE: this magic number was determined by experiment to be 1.1 (when 6799b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * using fixed point arithmetic). There's no great merit to the value 6800b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * below, however it only affects the limit used for checking for 6801b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * internal calculation errors, not the actual limit imposed by 6802b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * pngvalid on the output errors. 6803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6804b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari that->pm->limit += pow( 6805b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# if DIGITIZE 6806b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1.1 6807b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# else 6808b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1. 6809b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 6810b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /255, data.gamma); 6811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 6815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* With no gamma correction a large error comes from the truncation of the 6817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * calculation in the 8 bit case, allow for that here. 6818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6819b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (that->this.bit_depth != 16 && !pm->assume_16_bit_calculations) 6820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->pm->limit += 4E-3; 6821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6824b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6825b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_rgb_to_gray_set(PNG_CONST image_transform *this, 6826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 6827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int error_action = 1; /* no error, no defines in png.h */ 6829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 6831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_rgb_to_gray(pp, error_action, data.red_to_set, data.green_to_set); 6832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 6833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_rgb_to_gray_fixed(pp, error_action, data.red_to_set, 6834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik data.green_to_set); 6835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 6836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_cHRM_SUPPORTED 6838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->pm->current_encoding != 0) 6839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* We have an encoding so a cHRM chunk may have been set; if so then 6841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * check that the libpng APIs give the correct (X,Y,Z) values within 6842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * some margin of error for the round trip through the chromaticity 6843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * form. 6844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 6846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_function png_get_cHRM_XYZ 6847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_form "FP" 6848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_type double 6849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_cvt(x) (x) 6850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 6851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_function png_get_cHRM_XYZ_fixed 6852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_form "fixed" 6853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_type png_fixed_point 6854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define API_cvt(x) ((double)(x)/PNG_FP_1) 6855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 6856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik API_type rX, gX, bX; 6858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik API_type rY, gY, bY; 6859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik API_type rZ, gZ, bZ; 6860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((API_function(pp, pi, &rX, &rY, &rZ, &gX, &gY, &gZ, &bX, &bY, &bZ) 6862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik & PNG_INFO_cHRM) != 0) 6863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxe; 6865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *el; 6866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik color_encoding e, o; 6867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Expect libpng to return a normalized result, but the original 6869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * color space encoding may not be normalized. 6870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_current_encoding(that->pm, &o); 6872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik normalize_color_encoding(&o); 6873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Sanity check the pngvalid code - the coefficients should match 6875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the normalized Y values of the encoding unless they were 6876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * overridden. 6877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (data.red_to_set == -1 && data.green_to_set == -1 && 6879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (fabs(o.red.Y - data.red_coefficient) > DBL_EPSILON || 6880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fabs(o.green.Y - data.green_coefficient) > DBL_EPSILON || 6881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fabs(o.blue.Y - data.blue_coefficient) > DBL_EPSILON)) 6882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "internal pngvalid cHRM coefficient error"); 6883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Generate a colour space encoding. */ 6885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.gamma = o.gamma; /* not used */ 6886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.red.X = API_cvt(rX); 6887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.red.Y = API_cvt(rY); 6888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.red.Z = API_cvt(rZ); 6889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.green.X = API_cvt(gX); 6890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.green.Y = API_cvt(gY); 6891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.green.Z = API_cvt(gZ); 6892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.blue.X = API_cvt(bX); 6893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.blue.Y = API_cvt(bY); 6894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik e.blue.Z = API_cvt(bZ); 6895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This should match the original one from the png_modifier, within 6897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the range permitted by the libpng fixed point representation. 6898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik maxe = 0; 6900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik el = "-"; /* Set to element name with error */ 6901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define CHECK(col,x)\ 6903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik {\ 6904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double err = fabs(o.col.x - e.col.x);\ 6905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (err > maxe)\ 6906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik {\ 6907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik maxe = err;\ 6908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik el = #col "(" #x ")";\ 6909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik }\ 6910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(red,X) 6913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(red,Y) 6914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(red,Z) 6915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(green,X) 6916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(green,Y) 6917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(green,Z) 6918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(blue,X) 6919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(blue,Y) 6920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik CHECK(blue,Z) 6921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Here in both fixed and floating cases to check the values read 6923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * from the cHRm chunk. PNG uses fixed point in the cHRM chunk, so 6924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * we can't expect better than +/-.5E-5 on the result, allow 1E-5. 6925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (maxe >= 1E-5) 6927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 6929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char buffer[256]; 6930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, API_form); 6932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, " cHRM "); 6933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, el); 6934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, " error: "); 6935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, sizeof buffer, pos, maxe, 7); 6936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, " "); 6937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Print the color space without the gamma value: */ 6938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat_color_encoding(buffer, sizeof buffer, pos, &o, 0); 6939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, " -> "); 6940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat_color_encoding(buffer, sizeof buffer, pos, &e, 0); 6941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, buffer); 6943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 6946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif /* READ_cHRM */ 6947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 6949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 6950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6951b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 6952b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this, 6953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 6954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 6955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 6956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((that->colour_type & PNG_COLOR_MASK_COLOR) != 0) 6957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double gray, err; 6959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_PALETTE) 6961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_convert_PLTE(that); 6962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Image now has RGB channels... */ 6964b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# if DIGITIZE 6965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 6966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_modifier *pm = display->pm; 6967b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari const unsigned int sample_depth = that->sample_depth; 6968b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari const unsigned int calc_depth = (pm->assume_16_bit_calculations ? 16 : 6969b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari sample_depth); 6970b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari const unsigned int gamma_depth = (sample_depth == 16 ? 16 : 6971b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari (pm->assume_16_bit_calculations ? PNG_MAX_GAMMA_8 : sample_depth)); 6972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int isgray; 6973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double r, g, b; 6974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double rlo, rhi, glo, ghi, blo, bhi, graylo, grayhi; 6975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Do this using interval arithmetic, otherwise it is too difficult to 6977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * handle the errors correctly. 6978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 6979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * To handle the gamma correction work out the upper and lower bounds 6980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of the digitized value. Assume rounding here - normally the values 6981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * will be identical after this operation if there is only one 6982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transform, feel free to delete the png_error checks on this below in 6983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the future (this is just me trying to ensure it works!) 6984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 6985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik r = rlo = rhi = that->redf; 6986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik rlo -= that->rede; 6987b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari rlo = digitize(rlo, calc_depth, 1/*round*/); 6988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik rhi += that->rede; 6989b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari rhi = digitize(rhi, calc_depth, 1/*round*/); 6990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik g = glo = ghi = that->greenf; 6992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik glo -= that->greene; 6993b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari glo = digitize(glo, calc_depth, 1/*round*/); 6994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ghi += that->greene; 6995b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ghi = digitize(ghi, calc_depth, 1/*round*/); 6996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 6997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik b = blo = bhi = that->bluef; 6998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik blo -= that->bluee; 6999b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari blo = digitize(blo, calc_depth, 1/*round*/); 7000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bhi += that->greene; 7001b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari bhi = digitize(bhi, calc_depth, 1/*round*/); 7002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik isgray = r==g && g==b; 7004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (data.gamma != 1) 7006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double power = 1/data.gamma; 7008b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari PNG_CONST double abse = calc_depth == 16 ? .5/65535 : .5/255; 7009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 'abse' is the absolute error permitted in linear calculations. It 7011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is used here to capture the error permitted in the handling 7012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (undoing) of the gamma encoding. Once again digitization occurs 7013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to handle the upper and lower bounds of the values. This is 7014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * where the real errors are introduced. 7015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik r = pow(r, power); 7017b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari rlo = digitize(pow(rlo, power)-abse, calc_depth, 1); 7018b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari rhi = digitize(pow(rhi, power)+abse, calc_depth, 1); 7019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik g = pow(g, power); 7021b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari glo = digitize(pow(glo, power)-abse, calc_depth, 1); 7022b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ghi = digitize(pow(ghi, power)+abse, calc_depth, 1); 7023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik b = pow(b, power); 7025b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari blo = digitize(pow(blo, power)-abse, calc_depth, 1); 7026b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari bhi = digitize(pow(bhi, power)+abse, calc_depth, 1); 7027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now calculate the actual gray values. Although the error in the 7030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * coefficients depends on whether they were specified on the command 7031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * line (in which case truncation to 15 bits happened) or not (rounding 7032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * was used) the maxium error in an individual coefficient is always 7033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 1/32768, because even in the rounding case the requirement that 7034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * coefficients add up to 32768 can cause a larger rounding error. 7035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 7036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The only time when rounding doesn't occur in 1.5.5 and later is when 7037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the non-gamma code path is used for less than 16 bit data. 7038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gray = r * data.red_coefficient + g * data.green_coefficient + 7040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik b * data.blue_coefficient; 7041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7043b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari PNG_CONST int do_round = data.gamma != 1 || calc_depth == 16; 7044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double ce = 1. / 32768; 7045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7046b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari graylo = digitize(rlo * (data.red_coefficient-ce) + 7047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik glo * (data.green_coefficient-ce) + 7048b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari blo * (data.blue_coefficient-ce), gamma_depth, do_round); 7049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (graylo <= 0) 7050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik graylo = 0; 7051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7052b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari grayhi = digitize(rhi * (data.red_coefficient+ce) + 7053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ghi * (data.green_coefficient+ce) + 7054b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari bhi * (data.blue_coefficient+ce), gamma_depth, do_round); 7055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (grayhi >= 1) 7056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik grayhi = 1; 7057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And invert the gamma. */ 7060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (data.gamma != 1) 7061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double power = data.gamma; 7063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gray = pow(gray, power); 7065b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari graylo = digitize(pow(graylo, power), sample_depth, 1); 7066b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari grayhi = digitize(pow(grayhi, power), sample_depth, 1); 7067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now the error can be calculated. 7070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 7071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * If r==g==b because there is no overall gamma correction libpng 7072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * currently preserves the original value. 7073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (isgray) 7075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik err = (that->rede + that->greene + that->bluee)/3; 7076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik err = fabs(grayhi-gray); 7080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fabs(gray - graylo) > err) 7081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik err = fabs(graylo-gray); 7082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check that this worked: */ 7084b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (err > pm->limit) 7085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 7087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char buffer[128]; 7088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error "); 7090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(buffer, sizeof buffer, pos, err, 6); 7091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(buffer, sizeof buffer, pos, " exceeds limit "); 7092b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6); 7093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, buffer); 7094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7097b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# else /* DIGITIZE */ 7098b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 7099b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double r = that->redf; 7100b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double re = that->rede; 7101b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double g = that->greenf; 7102b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double ge = that->greene; 7103b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double b = that->bluef; 7104b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double be = that->bluee; 7105b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7106b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* The true gray case involves no math. */ 7107b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (r == g && r == b) 7108b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 7109b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari gray = r; 7110b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari err = re; 7111b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (err < ge) err = ge; 7112b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (err < be) err = be; 7113b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 7114b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7115b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else if (data.gamma == 1) 7116b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 7117b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* There is no need to do the conversions to and from linear space, 7118b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * so the calculation should be a lot more accurate. There is a 7119b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * built in 1/32768 error in the coefficients because they only have 7120b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 15 bits and are adjusted to make sure they add up to 32768, so 7121b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * the result may have an additional error up to 1/32768. (Note 7122b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * that adding the 1/32768 here avoids needing to increase the 7123b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * global error limits to take this into account.) 7124b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 7125b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari gray = r * data.red_coefficient + g * data.green_coefficient + 7126b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari b * data.blue_coefficient; 7127b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari err = re * data.red_coefficient + ge * data.green_coefficient + 7128b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari be * data.blue_coefficient + 1./32768 + gray * 5 * DBL_EPSILON; 7129b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 7130b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7131b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 7132b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 7133b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* The calculation happens in linear space, and this produces much 7134b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * wider errors in the encoded space. These are handled here by 7135b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * factoring the errors in to the calculation. There are two table 7136b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * lookups in the calculation and each introduces a quantization 7137b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * error defined by the table size. 7138b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 7139b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari PNG_CONST png_modifier *pm = display->pm; 7140b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double in_qe = (that->sample_depth > 8 ? .5/65535 : .5/255); 7141b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double out_qe = (that->sample_depth > 8 ? .5/65535 : 7142b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari (pm->assume_16_bit_calculations ? .5/(1<<PNG_MAX_GAMMA_8) : 7143b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari .5/255)); 7144b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double rhi, ghi, bhi, grayhi; 7145b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double g1 = 1/data.gamma; 7146b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7147b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari rhi = r + re + in_qe; if (rhi > 1) rhi = 1; 7148b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari r -= re + in_qe; if (r < 0) r = 0; 7149b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari ghi = g + ge + in_qe; if (ghi > 1) ghi = 1; 7150b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari g -= ge + in_qe; if (g < 0) g = 0; 7151b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari bhi = b + be + in_qe; if (bhi > 1) bhi = 1; 7152b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari b -= be + in_qe; if (b < 0) b = 0; 7153b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7154b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari r = pow(r, g1)*(1-DBL_EPSILON); rhi = pow(rhi, g1)*(1+DBL_EPSILON); 7155b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari g = pow(g, g1)*(1-DBL_EPSILON); ghi = pow(ghi, g1)*(1+DBL_EPSILON); 7156b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari b = pow(b, g1)*(1-DBL_EPSILON); bhi = pow(bhi, g1)*(1+DBL_EPSILON); 7157b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7158b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Work out the lower and upper bounds for the gray value in the 7159b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * encoded space, then work out an average and error. Remove the 7160b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * previously added input quantization error at this point. 7161b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 7162b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari gray = r * data.red_coefficient + g * data.green_coefficient + 7163b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari b * data.blue_coefficient - 1./32768 - out_qe; 7164b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (gray <= 0) 7165b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari gray = 0; 7166b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 7167b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 7168b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari gray *= (1 - 6 * DBL_EPSILON); 7169b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari gray = pow(gray, data.gamma) * (1-DBL_EPSILON); 7170b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 7171b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7172b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari grayhi = rhi * data.red_coefficient + ghi * data.green_coefficient + 7173b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari bhi * data.blue_coefficient + 1./32768 + out_qe; 7174b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari grayhi *= (1 + 6 * DBL_EPSILON); 7175b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (grayhi >= 1) 7176b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari grayhi = 1; 7177b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 7178b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari grayhi = pow(grayhi, data.gamma) * (1+DBL_EPSILON); 7179b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7180b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari err = (grayhi - gray) / 2; 7181b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari gray = (grayhi + gray) / 2; 7182b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7183b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (err <= in_qe) 7184b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari err = gray * DBL_EPSILON; 7185b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7186b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 7187b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari err -= in_qe; 7188b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7189b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Validate that the error is within limits (this has caused 7190b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * problems before, it's much easier to detect them here.) 7191b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 7192b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (err > pm->limit) 7193b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 7194b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari size_t pos = 0; 7195b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari char buffer[128]; 7196b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 7197b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pos = safecat(buffer, sizeof buffer, pos, "rgb_to_gray error "); 7198b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pos = safecatd(buffer, sizeof buffer, pos, err, 6); 7199b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pos = safecat(buffer, sizeof buffer, pos, " exceeds limit "); 7200b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pos = safecatd(buffer, sizeof buffer, pos, pm->limit, 6); 7201b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_error(pp, buffer); 7202b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 7203b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 7204b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 7205b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif /* !DIGITIZE */ 7206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluef = that->greenf = that->redf = gray; 7208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluee = that->greene = that->rede = err; 7209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The sBIT is the minium of the three colour channel sBITs. */ 7211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->red_sBIT > that->green_sBIT) 7212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->red_sBIT = that->green_sBIT; 7213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->red_sBIT > that->blue_sBIT) 7214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->red_sBIT = that->blue_sBIT; 7215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->blue_sBIT = that->green_sBIT = that->red_sBIT; 7216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And remove the colour bit in the type: */ 7218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_RGB) 7219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_GRAY; 7220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) 7221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; 7222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 7225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7227b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 7228b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_rgb_to_gray_add(image_transform *this, 7229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth) 7230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(bit_depth) 7232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 7234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 7235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (colour_type & PNG_COLOR_MASK_COLOR) != 0; 7237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef data 7240b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(rgb_to_gray); 7241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 7242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(rgb_to_gray) 7243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef image_transform_ini 7244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define image_transform_ini image_transform_default_ini 7245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */ 7246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_BACKGROUND_SUPPORTED 7248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_background(png_structp, png_const_color_16p background_color, 7249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * int background_gamma_code, int need_expand, double background_gamma) 7250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_set_background_fixed(png_structp, png_const_color_16p background_color, 7251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * int background_gamma_code, int need_expand, 7252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_fixed_point background_gamma) 7253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 7254b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * This ignores the gamma (at present.) 7255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik*/ 7256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define data ITDATA(background) 7257b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic image_pixel data; 7258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7259b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7260b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_background_set(PNG_CONST image_transform *this, 7261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 7262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type, bit_depth; 7264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte random_bytes[8]; /* 8 bytes - 64 bits - the biggest pixel */ 7265b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int expand; 7266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color_16 back; 7267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* We need a background colour, because we don't know exactly what transforms 7269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * have been set we have to supply the colour in the original file format and 7270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * so we need to know what that is! The background colour is stored in the 7271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transform_display. 7272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik RANDOMIZE(random_bytes); 7274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Read the random value, for colour type 3 the background colour is actually 7276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * expressed as a 24bit rgb, not an index. 7277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik colour_type = that->this.colour_type; 7279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type == 3) 7280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik colour_type = PNG_COLOR_TYPE_RGB; 7282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_depth = 8; 7283b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari expand = 0; /* passing in an RGB not a pixel index */ 7284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7287b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 7288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_depth = that->this.bit_depth; 7289b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari expand = 1; 7290b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 7291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_init(&data, random_bytes, colour_type, 7293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bit_depth, 0/*x*/, 0/*unused: palette*/); 7294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Extract the background colour from this image_pixel, but make sure the 7296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * unused fields of 'back' are garbage. 7297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik RANDOMIZE(back); 7299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type & PNG_COLOR_MASK_COLOR) 7301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik back.red = (png_uint_16)data.red; 7303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik back.green = (png_uint_16)data.green; 7304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik back.blue = (png_uint_16)data.blue; 7305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik back.gray = (png_uint_16)data.red; 7309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 7311b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0); 7312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7313b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, expand, 0); 7314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 7317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7319b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7320b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_background_mod(PNG_CONST image_transform *this, 7321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 7322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 7323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for tRNS first: */ 7325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->have_tRNS && that->colour_type != PNG_COLOR_TYPE_PALETTE) 7326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel_add_alpha(that, &display->this); 7327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is only necessary if the alpha value is less than 1. */ 7329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->alphaf < 1) 7330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now we do the background calculation without any gamma correction. */ 7332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->alphaf <= 0) 7333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->redf = data.redf; 7335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->greenf = data.greenf; 7336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluef = data.bluef; 7337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->rede = data.rede; 7339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->greene = data.greene; 7340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluee = data.bluee; 7341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->red_sBIT= data.red_sBIT; 7343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->green_sBIT= data.green_sBIT; 7344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->blue_sBIT= data.blue_sBIT; 7345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* 0 < alpha < 1 */ 7348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double alf = 1 - that->alphaf; 7350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->redf = that->redf * that->alphaf + data.redf * alf; 7352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->rede = that->rede * that->alphaf + data.rede * alf + 7353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik DBL_EPSILON; 7354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->greenf = that->greenf * that->alphaf + data.greenf * alf; 7355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->greene = that->greene * that->alphaf + data.greene * alf + 7356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik DBL_EPSILON; 7357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluef = that->bluef * that->alphaf + data.bluef * alf; 7358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->bluee = that->bluee * that->alphaf + data.bluee * alf + 7359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik DBL_EPSILON; 7360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Remove the alpha type and set the alpha (not in that order.) */ 7363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alphaf = 1; 7364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->alphae = 0; 7365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (that->colour_type == PNG_COLOR_TYPE_RGB_ALPHA) 7367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_RGB; 7368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) 7369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik that->colour_type = PNG_COLOR_TYPE_GRAY; 7370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* PNG_COLOR_TYPE_PALETTE is not changed */ 7371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 7374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define image_transform_png_set_background_add image_transform_default_add 7377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef data 7379b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(background); 7380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#undef PT 7381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define PT ITSTRUCT(background) 7382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_BACKGROUND_SUPPORTED */ 7383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This may just be 'end' if all the transforms are disabled! */ 7385b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic image_transform *PNG_CONST image_transform_first = &PT; 7386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7387b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7388b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_enable(PNG_CONST char *name) 7389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Everything starts out enabled, so if we see an 'enable' disabled 7391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * everything else the first time round. 7392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static int all_disabled = 0; 7394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int found_it = 0; 7395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform *list = image_transform_first; 7396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (list != &image_transform_end) 7398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (strcmp(list->name, name) == 0) 7400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list->enable = 1; 7402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik found_it = 1; 7403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (!all_disabled) 7405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list->enable = 0; 7406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list = list->list; 7408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik all_disabled = 1; 7411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!found_it) 7413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: --transform-enable=%s: unknown transform\n", 7415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik name); 7416b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 7417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7420b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7421b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktransform_disable(PNG_CONST char *name) 7422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform *list = image_transform_first; 7424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (list != &image_transform_end) 7426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (strcmp(list->name, name) == 0) 7428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list->enable = 0; 7430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 7431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list = list->list; 7434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: --transform-disable=%s: unknown transform\n", 7437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik name); 7438b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 7439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7441b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7442b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_reset_count(void) 7443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform *next = image_transform_first; 7445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int count = 0; 7446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (next != &image_transform_end) 7448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik next->local_use = 0; 7450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik next->next = 0; 7451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik next = next->list; 7452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++count; 7453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This can only happen if we every have more than 32 transforms (excluding 7456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the end) in the list. 7457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (count > 32) abort(); 7459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7461b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 7462b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_test_counter(png_uint_32 counter, unsigned int max) 7463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Test the list to see if there is any point contining, given a current 7465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * counter and a 'max' value. 7466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform *next = image_transform_first; 7468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (next != &image_transform_end) 7470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For max 0 or 1 continue until the counter overflows: */ 7472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik counter >>= 1; 7473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Continue if any entry hasn't reacked the max. */ 7475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (max > 1 && next->local_use < max) 7476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 7477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik next = next->list; 7478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return max <= 1 && counter == 0; 7481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7483b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 7484b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_add(PNG_CONST image_transform **this, unsigned int max, 7485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 counter, char *name, size_t sizeof_name, size_t *pos, 7486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type, png_byte bit_depth) 7487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (;;) /* until we manage to add something */ 7489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 mask; 7491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform *list; 7492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Find the next counter value, if the counter is zero this is the start 7494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of the list. This routine always returns the current counter (not the 7495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * next) so it returns 0 at the end and expects 0 at the beginning. 7496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (counter == 0) /* first time */ 7498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_transform_reset_count(); 7500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (max <= 1) 7501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik counter = 1; 7502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik counter = random_32(); 7504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* advance the counter */ 7506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (max) 7508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 0: ++counter; break; 7510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 1: counter <<= 1; break; 7511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: counter = random_32(); break; 7512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now add all these items, if possible */ 7516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *this = &image_transform_end; 7517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list = image_transform_first; 7518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mask = 1; 7519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Go through the whole list adding anything that the counter selects: */ 7521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (list != &image_transform_end) 7522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((counter & mask) != 0 && list->enable && 7524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (max == 0 || list->local_use < max)) 7525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Candidate to add: */ 7527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (list->add(list, this, colour_type, bit_depth) || max == 0) 7528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Added, so add to the name too. */ 7530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *pos = safecat(name, sizeof_name, *pos, " +"); 7531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *pos = safecat(name, sizeof_name, *pos, list->name); 7532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Not useful and max>0, so remove it from *this: */ 7537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *this = list->next; 7538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list->next = 0; 7539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And, since we know it isn't useful, stop it being added again 7541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in this run: 7542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list->local_use = max; 7544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik mask <<= 1; 7548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik list = list->list; 7549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now if anything was added we have something to do. */ 7552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (*this != &image_transform_end) 7553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return counter; 7554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Nothing added, but was there anything in there to add? */ 7556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!image_transform_test_counter(counter, max)) 7557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 7558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef THIS_IS_THE_PROFORMA 7562b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7563b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_@_set(PNG_CONST image_transform *this, 7564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_display *that, png_structp pp, png_infop pi) 7565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_@(pp); 7567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->set(this->next, that, pp, pi); 7568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7570b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7571b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_@_mod(PNG_CONST image_transform *this, 7572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik image_pixel *that, png_const_structp pp, 7573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST transform_display *display) 7574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next->mod(this->next, that, pp, display); 7576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7578b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 7579b50c217251b086440efcdb273c22f86a06c80cbaChris Craikimage_transform_png_set_@_add(image_transform *this, 7580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform **that, char *name, size_t sizeof_name, 7581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t *pos, png_byte colour_type, png_byte bit_depth) 7582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik this->next = *that; 7584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *that = this; 7585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *pos = safecat(name, sizeof_name, *pos, " +@"); 7587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 7589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7591b50c217251b086440efcdb273c22f86a06c80cbaChris CraikIT(@); 7592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 7593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_quantize(png_structp, png_colorp palette, int num_palette, 7595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * int maximum_colors, png_const_uint_16p histogram, int full_quantize) 7596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 7597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Very difficult to validate this! 7598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The data layout transforms are handled by swapping our own channel data, 7602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * necessarily these need to happen at the end of the transform list because the 7603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * semantic of the channels changes after these are executed. Some of these, 7604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * like set_shift and set_packing, can't be done at present because they change 7605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the layout of the data at the sub-sample level so sample() won't get the 7606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * right answer. 7607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_invert_alpha */ 7609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_bgr */ 7612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_swap_alpha */ 7615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_swap */ 7618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_filler, (png_structp png_ptr, png_uint_32 filler, int flags)); */ 7621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_add_alpha, (png_structp png_ptr, png_uint_32 filler, int flags)); */ 7624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_packing */ 7627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_packswap */ 7630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_invert_mono */ 7633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_set_shift(png_structp, png_const_color_8p true_bits) */ 7636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*NOTE: TBD NYI */ 7637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7638b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7639b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_transform_test(png_modifier *pm) 7640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type = 0; 7642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth = 0; 7643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int palette_number = 0; 7644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7645b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (next_format(&colour_type, &bit_depth, &palette_number, 0)) 7646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 counter = 0; 7648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t base_pos; 7649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[64]; 7650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base_pos = safecat(name, sizeof name, 0, "transform:"); 7652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (;;) 7654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = base_pos; 7656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST image_transform *list = 0; 7657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 'max' is currently hardwired to '1'; this should be settable on the 7659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * command line. 7660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik counter = image_transform_add(&list, 1/*max*/, counter, 7662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik name, sizeof name, &pos, colour_type, bit_depth); 7663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (counter == 0) 7665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 7666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The command line can change this to checking interlaced images. */ 7668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik do 7669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->repeat = 0; 7671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_test(pm, FILEID(colour_type, bit_depth, palette_number, 7672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->interlace_type, 0, 0, 0), list, name); 7673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 7675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 7676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (pm->repeat); 7678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ 7682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/********************************* GAMMA TESTS ********************************/ 7684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_GAMMA_SUPPORTED 7685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Reader callbacks and implementations, where they differ from the standard 7686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * ones. 7687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7688b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct gamma_display 7689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display this; 7691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Parameters */ 7693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_modifier* pm; 7694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double file_gamma; 7695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double screen_gamma; 7696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double background_gamma; 7697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte sbit; 7698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int threshold_test; 7699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int use_input_precision; 7700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int scale16; 7701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int expand16; 7702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_background; 7703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color_16 background_color; 7704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Local variables */ 7706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxerrout; 7707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxerrpc; 7708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxerrabs; 7709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} gamma_display; 7710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define ALPHA_MODE_OFFSET 4 7712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7713b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7714b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_display_init(gamma_display *dp, png_modifier *pm, png_uint_32 id, 7715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double file_gamma, double screen_gamma, png_byte sbit, int threshold_test, 7716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int use_input_precision, int scale16, int expand16, 7717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_background, PNG_CONST png_color_16 *pointer_to_the_background_color, 7718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double background_gamma) 7719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Standard fields */ 7721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/, 7722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_update_info); 7723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Parameter fields */ 7725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->pm = pm; 7726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->file_gamma = file_gamma; 7727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->screen_gamma = screen_gamma; 7728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->background_gamma = background_gamma; 7729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->sbit = sbit; 7730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->threshold_test = threshold_test; 7731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->use_input_precision = use_input_precision; 7732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->scale16 = scale16; 7733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->expand16 = expand16; 7734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->do_background = do_background; 7735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_background && pointer_to_the_background_color != 0) 7736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->background_color = *pointer_to_the_background_color; 7737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memset(&dp->background_color, 0, sizeof dp->background_color); 7739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Local variable fields */ 7741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->maxerrout = dp->maxerrpc = dp->maxerrabs = 0; 7742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7744b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7745b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi) 7746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Reuse the standard stuff as appropriate. */ 7748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_part1(&dp->this, pp, pi); 7749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If requested strip 16 to 8 bits - this is handled automagically below 7751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * because the output bit depth is read from the library. Note that there 7752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * are interactions with sBIT but, internally, libpng makes sbit at most 7753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_MAX_GAMMA_8 when doing the following. 7754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->scale16) 7756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED 7757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_scale_16(pp); 7758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following works both in 1.5.4 and earlier versions: */ 7760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_16_TO_8_SUPPORTED 7761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_strip_16(pp); 7762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "scale16 (16 to 8 bit conversion) not supported"); 7764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->expand16) 7768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_EXPAND_16_SUPPORTED 7769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_expand_16(pp); 7770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "expand16 (8 to 16 bit conversion) not supported"); 7772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->do_background >= ALPHA_MODE_OFFSET) 7775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_ALPHA_MODE_SUPPORTED 7777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This tests the alpha mode handling, if supported. */ 7779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int mode = dp->do_background - ALPHA_MODE_OFFSET; 7780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The gamma value is the output gamma, and is in the standard, 7782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * non-inverted, represenation. It provides a default for the PNG file 7783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * gamma, but since the file has a gAMA chunk this does not matter. 7784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double sg = dp->screen_gamma; 7786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifndef PNG_FLOATING_POINT_SUPPORTED 7787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_fixed_point g = fix(sg); 7788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 7791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_alpha_mode(pp, mode, sg); 7792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_alpha_mode_fixed(pp, mode, g); 7794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* However, for the standard Porter-Duff algorithm the output defaults 7797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to be linear, so if the test requires non-linear output it must be 7798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * corrected here. 7799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (mode == PNG_ALPHA_STANDARD && sg != 1) 7801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 7803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_gamma(pp, sg, dp->file_gamma); 7804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_fixed_point f = fix(dp->file_gamma); 7806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_gamma_fixed(pp, g, f); 7807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "alpha mode handling not supported"); 7812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set up gamma processing. */ 7818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 7819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_gamma(pp, dp->screen_gamma, dp->file_gamma); 7820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_fixed_point s = fix(dp->screen_gamma); 7823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_fixed_point f = fix(dp->file_gamma); 7824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_gamma_fixed(pp, s, f); 7825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->do_background) 7829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_BACKGROUND_SUPPORTED 7831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* NOTE: this assumes the caller provided the correct background gamma! 7832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double bg = dp->background_gamma; 7834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifndef PNG_FLOATING_POINT_SUPPORTED 7835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_fixed_point g = fix(bg); 7836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_FLOATING_POINT_SUPPORTED 7839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_background(pp, &dp->background_color, dp->do_background, 7840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0/*need_expand*/, bg); 7841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_background_fixed(pp, &dp->background_color, 7843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->do_background, 0/*need_expand*/, g); 7844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 7846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "png_set_background not supported"); 7847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int i = dp->this.use_update_info; 7853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Always do one call, even if use_update_info is 0. */ 7854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik do 7855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_update_info(pp, pi); 7856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (--i > 0); 7857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now we may get a different cbRow: */ 7860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_info_part2(&dp->this, pp, pi, 1 /*images*/); 7861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7863b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 7864b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_info(png_structp pp, png_infop pi) 7865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_info_imp(voidcast(gamma_display*, png_get_progressive_ptr(pp)), pp, 7867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pi); 7868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Validate a single component value - the routine gets the input and output 7871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * sample values as unscaled PNG component values along with a cache of all the 7872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * information required to validate the values. 7873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7874b50c217251b086440efcdb273c22f86a06c80cbaChris Craiktypedef struct validate_info 7875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp; 7877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_display *dp; 7878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte sbit; 7879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int use_input_precision; 7880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_background; 7881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int scale16; 7882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int sbit_max; 7883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int isbit_shift; 7884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int outmax; 7885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double gamma_correction; /* Overall correction required. */ 7887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double file_inverse; /* Inverse of file gamma. */ 7888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double screen_gamma; 7889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double screen_inverse; /* Inverse of screen gamma. */ 7890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double background_red; /* Linear background value, red or gray. */ 7892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double background_green; 7893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double background_blue; 7894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxabs; 7896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxpc; 7897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxcalc; 7898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxout; 7899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxout_total; /* Total including quantization error */ 7900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double outlog; 7901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int outquant; 7902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7903b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvalidate_info; 7904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7905b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 7906b50c217251b086440efcdb273c22f86a06c80cbaChris Craikinit_validate_info(validate_info *vi, gamma_display *dp, png_const_structp pp, 7907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int in_depth, int out_depth) 7908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 7909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int outmax = (1U<<out_depth)-1; 7910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->pp = pp; 7912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->dp = dp; 7913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (dp->sbit > 0 && dp->sbit < in_depth) 7915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->sbit = dp->sbit; 7917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->isbit_shift = in_depth - dp->sbit; 7918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->sbit = (png_byte)in_depth; 7923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->isbit_shift = 0; 7924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->sbit_max = (1U << vi->sbit)-1; 7927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This mimics the libpng threshold test, '0' is used to prevent gamma 7929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * correction in the validation test. 7930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->screen_gamma = dp->screen_gamma; 7932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fabs(vi->screen_gamma-1) < PNG_GAMMA_THRESHOLD) 7933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->screen_gamma = vi->screen_inverse = 0; 7934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->screen_inverse = 1/vi->screen_gamma; 7936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->use_input_precision = dp->use_input_precision; 7938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->outmax = outmax; 7939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->maxabs = abserr(dp->pm, in_depth, out_depth); 7940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->maxpc = pcerr(dp->pm, in_depth, out_depth); 7941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->maxcalc = calcerr(dp->pm, in_depth, out_depth); 7942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->maxout = outerr(dp->pm, in_depth, out_depth); 7943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->outquant = output_quantization_factor(dp->pm, in_depth, out_depth); 7944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->maxout_total = vi->maxout + vi->outquant * .5; 7945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->outlog = outlog(dp->pm, in_depth, out_depth); 7946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((dp->this.colour_type & PNG_COLOR_MASK_ALPHA) != 0 || 7948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (dp->this.colour_type == 3 && dp->this.is_transparent)) 7949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->do_background = dp->do_background; 7951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (vi->do_background != 0) 7953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double bg_inverse = 1/dp->background_gamma; 7955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double r, g, b; 7956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Caller must at least put the gray value into the red channel */ 7958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik r = dp->background_color.red; r /= outmax; 7959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik g = dp->background_color.green; g /= outmax; 7960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik b = dp->background_color.blue; b /= outmax; 7961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if 0 7963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* libpng doesn't do this optimization, if we do pngvalid will fail. 7964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 7965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fabs(bg_inverse-1) >= PNG_GAMMA_THRESHOLD) 7966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 7967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik r = pow(r, bg_inverse); 7969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik g = pow(g, bg_inverse); 7970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik b = pow(b, bg_inverse); 7971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->background_red = r; 7974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->background_green = g; 7975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->background_blue = b; 7976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 7978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 7979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->do_background = 0; 7980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (vi->do_background == 0) 7982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->background_red = vi->background_green = vi->background_blue = 0; 7983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->gamma_correction = 1/(dp->file_gamma*dp->screen_gamma); 7985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fabs(vi->gamma_correction-1) < PNG_GAMMA_THRESHOLD) 7986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->gamma_correction = 0; 7987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->file_inverse = 1/dp->file_gamma; 7989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fabs(vi->file_inverse-1) < PNG_GAMMA_THRESHOLD) 7990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->file_inverse = 0; 7991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->scale16 = dp->scale16; 7993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 7994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 7995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This function handles composition of a single non-alpha component. The 7996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * argument is the input sample value, in the range 0..1, and the alpha value. 7997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The result is the composed, linear, input sample. If alpha is less than zero 7998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this is the alpha component and the function should not be called! 7999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8000b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double 8001b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_component_compose(int do_background, double input_sample, double alpha, 8002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double background, int *compose) 8003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 8004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (do_background) 8005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_BACKGROUND_SUPPORTED 8007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_SCREEN: 8008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_FILE: 8009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_UNIQUE: 8010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Standard PNG background processing. */ 8011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha < 1) 8012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha > 0) 8014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik input_sample = input_sample * alpha + background * (1-alpha); 8016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (compose != NULL) 8017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *compose = 1; 8018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik input_sample = background; 8022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 8025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_ALPHA_MODE_SUPPORTED 8027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: 8028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: 8029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The components are premultiplied in either case and the output is 8030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * gamma encoded (to get standard Porter-Duff we expect the output 8031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * gamma to be set to 1.0!) 8032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: 8034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The optimization is that the partial-alpha entries are linear 8035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * while the opaque pixels are gamma encoded, but this only affects the 8036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * output encoding. 8037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha < 1) 8039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha > 0) 8041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik input_sample *= alpha; 8043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (compose != NULL) 8044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *compose = 1; 8045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik input_sample = 0; 8049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 8052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 8054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Standard cases where no compositing is done (so the component 8055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value is already correct.) 8056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(alpha) 8058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(background) 8059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik UNUSED(compose) 8060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return input_sample; 8064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 8065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This API returns the encoded *input* component, in the range 0..1 */ 8067b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double 8068b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi, 8069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int id, PNG_CONST unsigned int od, 8070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double alpha /* <0 for the alpha channel itself */, 8071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double background /* component background value */) 8072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 8073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int isbit = id >> vi->isbit_shift; 8074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int sbit_max = vi->sbit_max; 8075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int outmax = vi->outmax; 8076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int do_background = vi->do_background; 8077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double i; 8079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* First check on the 'perfect' result obtained from the digitized input 8081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value, id, and compare this against the actual digitized result, 'od'. 8082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'i' is the input result in the range 0..1: 8083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik i = isbit; i /= sbit_max; 8085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for the fast route: if we don't do any background composition or if 8087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this is the alpha channel ('alpha' < 0) or if the pixel is opaque then 8088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * just use the gamma_correction field to correct to the final output gamma. 8089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha == 1 /* opaque pixel component */ || !do_background 8091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_ALPHA_MODE_SUPPORTED 8092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik || do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_PNG 8093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 8094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik || (alpha < 0 /* alpha channel */ 8095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_ALPHA_MODE_SUPPORTED 8096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik && do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN 8097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 8098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik )) 8099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Then get the gamma corrected version of 'i' and compare to 'od', any 8101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * error less than .5 is insignificant - just quantization of the output 8102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value to the nearest digital value (nevertheless the error is still 8103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * recorded - it's interesting ;-) 8104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double encoded_sample = i; 8106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double encoded_error; 8107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* alpha less than 0 indicates the alpha channel, which is always linear 8109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha >= 0 && vi->gamma_correction > 0) 8111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoded_sample = pow(encoded_sample, vi->gamma_correction); 8112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoded_sample *= outmax; 8113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoded_error = fabs(od-encoded_sample); 8115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoded_error > vi->dp->maxerrout) 8117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->dp->maxerrout = encoded_error; 8118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoded_error < vi->maxout_total && encoded_error < vi->outlog) 8120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return i; 8121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The slow route - attempt to do linear calculations. */ 8124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There may be an error, or background processing is required, so calculate 8125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the actual sample values - unencoded light intensity values. Note that in 8126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * practice these are not completely unencoded because they include a 8127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'viewing correction' to decrease or (normally) increase the perceptual 8128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * contrast of the image. There's nothing we can do about this - we don't 8129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * know what it is - so assume the unencoded value is perceptually linear. 8130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double input_sample = i; /* In range 0..1 */ 8133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double output, error, encoded_sample, encoded_error; 8134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double es_lo, es_hi; 8135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int compose = 0; /* Set to one if composition done */ 8136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int output_is_encoded; /* Set if encoded to screen gamma */ 8137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int log_max_error = 1; /* Check maximum error values */ 8138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_charp pass = 0; /* Reason test passes (or 0 for fail) */ 8139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Convert to linear light (with the above caveat.) The alpha channel is 8141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * already linear. 8142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha >= 0) 8144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int tcompose; 8146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (vi->file_inverse > 0) 8148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik input_sample = pow(input_sample, vi->file_inverse); 8149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Handle the compose processing: */ 8151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tcompose = 0; 8152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik input_sample = gamma_component_compose(do_background, input_sample, 8153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha, background, &tcompose); 8154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tcompose) 8156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik compose = 1; 8157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And similarly for the output value, but we need to check the background 8160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * handling to linearize it correctly. 8161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output = od; 8163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output /= outmax; 8164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output_is_encoded = vi->screen_gamma > 0; 8166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha < 0) /* The alpha channel */ 8168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_ALPHA_MODE_SUPPORTED 8170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN) 8171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 8172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* In all other cases the output alpha channel is linear already, 8174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * don't log errors here, they are much larger in linear data. 8175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output_is_encoded = 0; 8177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik log_max_error = 0; 8178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_ALPHA_MODE_SUPPORTED 8182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* A component */ 8183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED && 8185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha < 1) /* the optimized case - linear output */ 8186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (alpha > 0) log_max_error = 0; 8188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output_is_encoded = 0; 8189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 8192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_is_encoded) 8194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output = pow(output, vi->screen_gamma); 8195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Calculate (or recalculate) the encoded_sample value and repeat the 8197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * check above (unnecessary if we took the fast route, but harmless.) 8198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoded_sample = input_sample; 8200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_is_encoded) 8201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoded_sample = pow(encoded_sample, vi->screen_inverse); 8202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoded_sample *= outmax; 8203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik encoded_error = fabs(od-encoded_sample); 8205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Don't log errors in the alpha channel, or the 'optimized' case, 8207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * neither are significant to the overall perception. 8208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (log_max_error && encoded_error > vi->dp->maxerrout) 8210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->dp->maxerrout = encoded_error; 8211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoded_error < vi->maxout_total) 8213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoded_error < vi->outlog) 8215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return i; 8216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Test passed but error is bigger than the log limit, record why the 8218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * test passed: 8219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pass = "less than maxout:\n"; 8221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* i: the original input value in the range 0..1 8224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * pngvalid calculations: 8226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * input_sample: linear result; i linearized and composed, range 0..1 8227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * encoded_sample: encoded result; input_sample scaled to ouput bit depth 8228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng calculations: 8230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * output: linear result; od scaled to 0..1 and linearized 8231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * od: encoded result from libpng 8232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now we have the numbers for real errors, both absolute values as as a 8235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * percentage of the correct value (output): 8236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik error = fabs(input_sample-output); 8238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (log_max_error && error > vi->dp->maxerrabs) 8240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->dp->maxerrabs = error; 8241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following is an attempt to ignore the tendency of quantization to 8243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * dominate the percentage errors for lower result values: 8244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (log_max_error && input_sample > .5) 8246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double percentage_error = error/input_sample; 8248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (percentage_error > vi->dp->maxerrpc) 8249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->dp->maxerrpc = percentage_error; 8250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now calculate the digitization limits for 'encoded_sample' using the 8253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'max' values. Note that maxout is in the encoded space but maxpc and 8254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * maxabs are in linear light space. 8255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * First find the maximum error in linear light space, range 0..1: 8257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double tmp = input_sample * vi->maxpc; 8260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tmp < vi->maxabs) tmp = vi->maxabs; 8261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If 'compose' is true the composition was done in linear space using 8262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * integer arithmetic. This introduces an extra error of +/- 0.5 (at 8263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * least) in the integer space used. 'maxcalc' records this, taking 8264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * into account the possibility that even for 16 bit output 8 bit space 8265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * may have been used. 8266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (compose && tmp < vi->maxcalc) tmp = vi->maxcalc; 8268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The 'maxout' value refers to the encoded result, to compare with 8270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this encode input_sample adjusted by the maximum error (tmp) above. 8271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik es_lo = encoded_sample - vi->maxout; 8273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (es_lo > 0 && input_sample-tmp > 0) 8275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double low_value = input_sample-tmp; 8277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_is_encoded) 8278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik low_value = pow(low_value, vi->screen_inverse); 8279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik low_value *= outmax; 8280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (low_value < es_lo) es_lo = low_value; 8281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Quantize this appropriately: */ 8283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik es_lo = ceil(es_lo / vi->outquant - .5) * vi->outquant; 8284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik es_lo = 0; 8288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik es_hi = encoded_sample + vi->maxout; 8290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (es_hi < outmax && input_sample+tmp < 1) 8292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double high_value = input_sample+tmp; 8294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_is_encoded) 8295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik high_value = pow(high_value, vi->screen_inverse); 8296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik high_value *= outmax; 8297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (high_value > es_hi) es_hi = high_value; 8298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik es_hi = floor(es_hi / vi->outquant + .5) * vi->outquant; 8300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik es_hi = outmax; 8304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The primary test is that the final encoded value returned by the 8307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * library should be between the two limits (inclusive) that were 8308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * calculated above. 8309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (od >= es_lo && od <= es_hi) 8311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The value passes, but we may need to log the information anyway. */ 8313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoded_error < vi->outlog) 8314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return i; 8315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pass == 0) 8317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pass = "within digitization limits:\n"; 8318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There has been an error in processing, or we need to log this 8322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value. 8323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double is_lo, is_hi; 8325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* pass is set at this point if either of the tests above would have 8327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * passed. Don't do these additional tests here - just log the 8328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * original [es_lo..es_hi] values. 8329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8330b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (pass == 0 && vi->use_input_precision && vi->dp->sbit) 8331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Ok, something is wrong - this actually happens in current libpng 8333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 16-to-8 processing. Assume that the input value (id, adjusted 8334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * for sbit) can be anywhere between value-.5 and value+.5 - quite a 8335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * large range if sbit is low. 8336b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 8337b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * NOTE: at present because the libpng gamma table stuff has been 8338b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * changed to use a rounding algorithm to correct errors in 8-bit 8339b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * calculations the precise sbit calculation (a shift) has been 8340b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * lost. This can result in up to a +/-1 error in the presence of 8341b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * an sbit less than the bit depth. 8342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8343b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# if PNG_LIBPNG_VER < 10700 8344b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define SBIT_ERROR .5 8345b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# else 8346b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define SBIT_ERROR 1. 8347b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 8348b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari double tmp = (isbit - SBIT_ERROR)/sbit_max; 8349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tmp <= 0) 8351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = 0; 8352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1) 8354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = pow(tmp, vi->file_inverse); 8355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = gamma_component_compose(do_background, tmp, alpha, background, 8357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik NULL); 8358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_is_encoded && tmp > 0 && tmp < 1) 8360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = pow(tmp, vi->screen_inverse); 8361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_lo = ceil(outmax * tmp - vi->maxout_total); 8363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (is_lo < 0) 8365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_lo = 0; 8366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8367b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari tmp = (isbit + SBIT_ERROR)/sbit_max; 8368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8369b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (tmp >= 1) 8370b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari tmp = 1; 8371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1) 8373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = pow(tmp, vi->file_inverse); 8374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = gamma_component_compose(do_background, tmp, alpha, background, 8376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik NULL); 8377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_is_encoded && tmp > 0 && tmp < 1) 8379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = pow(tmp, vi->screen_inverse); 8380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_hi = floor(outmax * tmp + vi->maxout_total); 8382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (is_hi > outmax) 8384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_hi = outmax; 8385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!(od < is_lo || od > is_hi)) 8387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoded_error < vi->outlog) 8389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return i; 8390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pass = "within input precision limits:\n"; 8392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* One last chance. If this is an alpha channel and the 16to8 8395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * option has been used and 'inaccurate' scaling is used then the 8396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bit reduction is obtained by simply using the top 8 bits of the 8397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value. 8398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This is only done for older libpng versions when the 'inaccurate' 8400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (chop) method of scaling was used. 8401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED 8403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# if PNG_LIBPNG_VER < 10504 8404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This may be required for other components in the future, 8405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * but at present the presence of gamma correction effectively 8406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * prevents the errors in the component scaling (I don't quite 8407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * understand why, but since it's better this way I care not 8408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to ask, JB 20110419.) 8409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pass == 0 && alpha < 0 && vi->scale16 && vi->sbit > 8 && 8411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi->sbit + vi->isbit_shift == 16) 8412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = ((id >> 8) - .5)/255; 8414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tmp > 0) 8416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_lo = ceil(outmax * tmp - vi->maxout_total); 8418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (is_lo < 0) is_lo = 0; 8419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_lo = 0; 8423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik tmp = ((id >> 8) + .5)/255; 8425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (tmp < 1) 8427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_hi = floor(outmax * tmp + vi->maxout_total); 8429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (is_hi > outmax) is_hi = outmax; 8430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_hi = outmax; 8434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!(od < is_lo || od > is_hi)) 8436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (encoded_error < vi->outlog) 8438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return i; 8439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pass = "within 8 bit limits:\n"; 8441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 8444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 8445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* !use_input_precision */ 8447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik is_lo = es_lo, is_hi = es_hi; 8448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Attempt to output a meaningful error/warning message: the message 8450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * output depends on the background/composite operation being performed 8451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * because this changes what parameters were actually used above. 8452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 8455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Need either 1/255 or 1/65535 precision here; 3 or 6 decimal 8456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * places. Just use outmax to work out which. 8457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int precision = (outmax >= 1000 ? 6 : 3); 8459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int use_input=1, use_background=0, do_compose=0; 8460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[256]; 8461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pass != 0) 8463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "\n\t"); 8464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Set up the various flags, the output_is_encoded flag above 8466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is also used below. do_compose is just a double check. 8467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (do_background) 8469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_BACKGROUND_SUPPORTED 8471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_SCREEN: 8472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_FILE: 8473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_UNIQUE: 8474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik use_background = (alpha >= 0 && alpha < 1); 8475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /*FALL THROUGH*/ 8476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 8477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_ALPHA_MODE_SUPPORTED 8478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: 8479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: 8480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: 8481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif /* ALPHA_MODE_SUPPORTED */ 8482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik do_compose = (alpha > 0 && alpha < 1); 8483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik use_input = (alpha != 0); 8484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 8487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the 'compose' flag */ 8491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (compose != do_compose) 8492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(vi->pp, "internal error (compose)"); 8493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* 'name' is the component name */ 8495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, name); 8496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "("); 8497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, id); 8498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (use_input || pass != 0/*logging*/) 8499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (isbit != id) 8501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* sBIT has reduced the precision of the input: */ 8503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, ", sbit("); 8504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, vi->sbit); 8505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "): "); 8506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, isbit); 8507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "/"); 8509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The output is either "id/max" or "id sbit(sbit): isbit/max" */ 8510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, vi->sbit_max); 8511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, ")"); 8513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* A component may have been multiplied (in linear space) by the 8515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * alpha value, 'compose' says whether this is relevant. 8516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (compose || pass != 0) 8518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If any form of composition is being done report our 8520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * calculated linear value here (the code above doesn't record 8521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the input value before composition is performed, so what 8522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * gets reported is the value after composition.) 8523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (use_input || pass != 0) 8525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (vi->file_inverse > 0) 8527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "^"); 8529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, vi->file_inverse, 2); 8530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "[linear]"); 8534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "*(alpha)"); 8536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, alpha, precision); 8537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now record the *linear* background value if it was used 8540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (this function is not passed the original, non-linear, 8541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value but it is contained in the test name.) 8542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (use_background) 8544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, use_input ? "+" : " "); 8546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "(background)"); 8547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, background, precision); 8548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "*"); 8549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, 1-alpha, precision); 8550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Report the calculated value (input_sample) and the linearized 8554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng value (output) unless this is just a component gamma 8555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * correction. 8556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (compose || alpha < 0 || pass != 0) 8558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, 8560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pass != 0 ? " =\n\t" : " = "); 8561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, input_sample, precision); 8562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " (libpng: "); 8563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, output, precision); 8564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, ")"); 8565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Finally report the output gamma encoding, if any. */ 8567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_is_encoded) 8568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " ^"); 8570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, vi->screen_inverse, 2); 8571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "(to screen) ="); 8572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " [screen is linear] ="); 8576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((!compose && alpha >= 0) || pass != 0) 8579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pass != 0) /* logging */ 8581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "\n\t[overall:"); 8582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is the non-composition case, the internal linear 8584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * values are irrelevant (though the log below will reveal 8585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * them.) Output a much shorter warning/error message and report 8586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the overall gamma correction. 8587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (vi->gamma_correction > 0) 8589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " ^"); 8591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, vi->gamma_correction, 2); 8592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "(gamma correction) ="); 8593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, 8597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik " [no gamma correction] ="); 8598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pass != 0) 8600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "]"); 8601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is our calculated encoded_sample which should (but does 8604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * not) match od: 8605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, pass != 0 ? "\n\t" : " "); 8607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, is_lo, 1); 8608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " < "); 8609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, encoded_sample, 1); 8610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " (libpng: "); 8611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, od); 8612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, ")"); 8613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "/"); 8614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, outmax); 8615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, " < "); 8616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(msg, sizeof msg, pos, is_hi, 1); 8617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pass == 0) /* The error condition */ 8619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_WARNINGS_SUPPORTED 8621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_warning(vi->pp, msg); 8622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# else 8623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_warning(vi->pp, msg); 8624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 8625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* logging this value */ 8628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_verbose(&vi->dp->pm->this, vi->pp, pass, msg); 8629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return i; 8634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 8635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8636b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 8637b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_image_validate(gamma_display *dp, png_const_structp pp, 8638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi) 8639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 8640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Get some constants derived from the input and output file formats: */ 8641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_store* PNG_CONST ps = dp->this.ps; 8642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte in_ct = dp->this.colour_type; 8643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte in_bd = dp->this.bit_depth; 8644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 w = dp->this.w; 8645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_uint_32 h = dp->this.h; 8646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST size_t cbRow = dp->this.cbRow; 8647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte out_ct = png_get_color_type(pp, pi); 8648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte out_bd = png_get_bit_depth(pp, pi); 8649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There are three sources of error, firstly the quantization in the 8651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * file encoding, determined by sbit and/or the file depth, secondly 8652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the output (screen) gamma and thirdly the output file encoding. 8653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Since this API receives the screen and file gamma in double 8655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * precision it is possible to calculate an exact answer given an input 8656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * pixel value. Therefore we assume that the *input* value is exact - 8657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * sample/maxsample - calculate the corresponding gamma corrected 8658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * output to the limits of double precision arithmetic and compare with 8659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * what libpng returns. 8660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Since the library must quantize the output to 8 or 16 bits there is 8662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * a fundamental limit on the accuracy of the output of +/-.5 - this 8663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * quantization limit is included in addition to the other limits 8664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * specified by the paramaters to the API. (Effectively, add .5 8665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * everywhere.) 8666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The behavior of the 'sbit' paramter is defined by section 12.5 8668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (sample depth scaling) of the PNG spec. That section forces the 8669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * decoder to assume that the PNG values have been scaled if sBIT is 8670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * present: 8671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png-sample = floor( input-sample * (max-out/max-in) + .5); 8673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This means that only a subset of the possible PNG values should 8675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * appear in the input. However, the spec allows the encoder to use a 8676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * variety of approximations to the above and doesn't require any 8677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * restriction of the values produced. 8678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Nevertheless the spec requires that the upper 'sBIT' bits of the 8680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value stored in a PNG file be the original sample bits. 8681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Consequently the code below simply scales the top sbit bits by 8682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (1<<sbit)-1 to obtain an original sample value. 8683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Because there is limited precision in the input it is arguable that 8685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * an acceptable result is any valid result from input-.5 to input+.5. 8686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The basic tests below do not do this, however if 'use_input_precision' 8687b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * is set a subsequent test is performed above. 8688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int samples_per_pixel = (out_ct & 2U) ? 3U : 1U; 8690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int processing; 8691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 y; 8692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST store_palette_entry *in_palette = dp->this.palette; 8693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int in_is_transparent = dp->this.is_transparent; 8694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int out_npalette = -1; 8695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int out_is_transparent = 0; /* Just refers to the palette case */ 8696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_palette out_palette; 8697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik validate_info vi; 8698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check for row overwrite errors */ 8700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_image_check(dp->this.ps, pp, 0); 8701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Supply the input and output sample depths here - 8 for an indexed image, 8703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * otherwise the bit depth. 8704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_validate_info(&vi, dp, pp, in_ct==3?8:in_bd, out_ct==3?8:out_bd); 8706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik processing = (vi.gamma_correction > 0 && !dp->threshold_test) 8708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik || in_bd != out_bd || in_ct != out_ct || vi.do_background; 8709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* TODO: FIX THIS: MAJOR BUG! If the transformations all happen inside 8711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the palette there is no way of finding out, because libpng fails to 8712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * update the palette on png_read_update_info. Indeed, libpng doesn't 8713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * even do the required work until much later, when it doesn't have any 8714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * info pointer. Oops. For the moment 'processing' is turned off if 8715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * out_ct is palette. 8716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (in_ct == 3 && out_ct == 3) 8718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik processing = 0; 8719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (processing && out_ct == 3) 8721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_is_transparent = read_palette(out_palette, &out_npalette, pp, pi); 8722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<h; ++y) 8724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_bytep pRow = store_image_row(ps, pp, 0, y); 8726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte std[STANDARD_ROWMAX]; 8727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_row(pp, std, in_ct, in_bd, y); 8729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (processing) 8731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int x; 8733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (x=0; x<w; ++x) 8735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double alpha = 1; /* serves as a flag value */ 8737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Record the palette index for index images. */ 8739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int in_index = 8740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_ct == 3 ? sample(std, 3, in_bd, x, 0) : 256; 8741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int out_index = 8742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_ct == 3 ? sample(std, 3, out_bd, x, 0) : 256; 8743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Handle input alpha - png_set_background will cause the output 8745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * alpha to disappear so there is nothing to check. 8746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 || (in_ct == 3 && 8748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_is_transparent)) 8749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST unsigned int input_alpha = in_ct == 3 ? 8751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->this.palette[in_index].alpha : 8752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(std, in_ct, in_bd, x, samples_per_pixel); 8753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int output_alpha = 65536 /* as a flag value */; 8755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (out_ct == 3) 8757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (out_is_transparent) 8759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output_alpha = out_palette[out_index].alpha; 8760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0) 8763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output_alpha = sample(pRow, out_ct, out_bd, x, 8764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik samples_per_pixel); 8765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (output_alpha != 65536) 8767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha = gamma_component_validate("alpha", &vi, input_alpha, 8768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik output_alpha, -1/*alpha*/, 0/*background*/); 8769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* no alpha in output */ 8771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is a copy of the calculation of 'i' above in order to 8773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * have the alpha value to use in the background calculation. 8774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha = input_alpha >> vi.isbit_shift; 8776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha /= vi.sbit_max; 8777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Handle grayscale or RGB components. */ 8781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* grayscale */ 8782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)gamma_component_validate("gray", &vi, 8783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(std, in_ct, in_bd, x, 0), 8784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(pRow, out_ct, out_bd, x, 0), alpha/*component*/, 8785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik vi.background_red); 8786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* RGB or palette */ 8787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)gamma_component_validate("red", &vi, 8789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_ct == 3 ? in_palette[in_index].red : 8790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(std, in_ct, in_bd, x, 0), 8791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_ct == 3 ? out_palette[out_index].red : 8792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(pRow, out_ct, out_bd, x, 0), 8793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha/*component*/, vi.background_red); 8794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)gamma_component_validate("green", &vi, 8796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_ct == 3 ? in_palette[in_index].green : 8797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(std, in_ct, in_bd, x, 1), 8798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_ct == 3 ? out_palette[out_index].green : 8799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(pRow, out_ct, out_bd, x, 1), 8800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha/*component*/, vi.background_green); 8801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)gamma_component_validate("blue", &vi, 8803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik in_ct == 3 ? in_palette[in_index].blue : 8804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(std, in_ct, in_bd, x, 2), 8805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik out_ct == 3 ? out_palette[out_index].blue : 8806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sample(pRow, out_ct, out_bd, x, 2), 8807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik alpha/*component*/, vi.background_blue); 8808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (memcmp(std, pRow, cbRow) != 0) 8813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[64]; 8815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* No transform is expected on the threshold tests. */ 8817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sprintf(msg, "gamma: below threshold row %lu changed", 8818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)y); 8819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, msg); 8821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } /* row (y) loop */ 8823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->this.ps->validated = 1; 8825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 8826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8827b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI 8828b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_end(png_structp ppIn, png_infop pi) 8829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 8830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_structp pp = ppIn; 8831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_display *dp = voidcast(gamma_display*, png_get_progressive_ptr(pp)); 8832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!dp->this.speed) 8834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_image_validate(dp, pp, pi); 8835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik dp->this.ps->validated = 1; 8837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 8838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A single test run checking a gamma transformation. 8840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * maxabs: maximum absolute error as a fraction 8842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * maxout: maximum output error in the output units 8843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * maxpc: maximum percentage error (as a percentage) 8844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8845b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 8846b50c217251b086440efcdb273c22f86a06c80cbaChris Craikgamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn, 8847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte bit_depthIn, PNG_CONST int palette_numberIn, 8848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int interlace_typeIn, 8849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double file_gammaIn, PNG_CONST double screen_gammaIn, 8850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte sbitIn, PNG_CONST int threshold_testIn, 8851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *name, 8852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int use_input_precisionIn, PNG_CONST int scale16In, 8853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int expand16In, PNG_CONST int do_backgroundIn, 8854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_color_16 *bkgd_colorIn, double bkgd_gammaIn) 8855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 8856b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_display d; 8857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik context(&pmIn->this, fault); 8858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_display_init(&d, pmIn, FILEID(colour_typeIn, bit_depthIn, 8860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik palette_numberIn, interlace_typeIn, 0, 0, 0), 8861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik file_gammaIn, screen_gammaIn, sbitIn, 8862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik threshold_testIn, use_input_precisionIn, scale16In, 8863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik expand16In, do_backgroundIn, bkgd_colorIn, bkgd_gammaIn); 8864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 8866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_structp pp; 8868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_infop pi; 8869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gama_modification gama_mod; 8870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik srgb_modification srgb_mod; 8871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sbit_modification sbit_mod; 8872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* For the moment don't use the png_modifier support here. */ 8874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->encoding_counter = 0; 8875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_set_encoding(d.pm); /* Just resets everything */ 8876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->current_gamma = d.file_gamma; 8877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Make an appropriate modifier to set the PNG file gamma to the 8879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * given gamma value and the sBIT chunk to the given precision. 8880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 8881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->modifications = NULL; 8882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gama_modification_init(&gama_mod, d.pm, d.file_gamma); 8883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik srgb_modification_init(&srgb_mod, d.pm, 127 /*delete*/); 8884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.sbit > 0) 8885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sbit_modification_init(&sbit_mod, d.pm, d.sbit); 8886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modification_reset(d.pm->modifications); 8888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Get a png_struct for writing the image. */ 8890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pp = set_modifier_for_read(d.pm, &pi, d.this.id, name); 8891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik standard_palette_init(&d.this); 8892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Introduce the correct read function. */ 8894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.pm->this.progressive) 8895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Share the row function with the standard implementation. */ 8897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_progressive_read_fn(pp, &d, gamma_info, progressive_row, 8898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_end); 8899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now feed data into the reader until we reach the end: */ 8901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_progressive_read(d.pm, pp, pi); 8902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* modifier_read expects a png_modifier* */ 8906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_set_read_fn(pp, d.pm, modifier_read); 8907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Check the header values: */ 8909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_read_info(pp, pi); 8910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Process the 'info' requirements. Only one image is generated */ 8912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_info_imp(&d, pp, pi); 8913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sequential_row(&d.this, pp, pi, -1, 0); 8915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!d.this.speed) 8917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_image_validate(&d, pp, pi); 8918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 8919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.this.ps->validated = 1; 8920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_reset(d.pm); 8923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.pm->log && !d.threshold_test && !d.this.speed) 8925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "%d bit %s %s: max error %f (%.2g, %2g%%)\n", 8926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.this.bit_depth, colour_types[d.this.colour_type], name, 8927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.maxerrout, d.maxerrabs, 100*d.maxerrpc); 8928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Log the summary values too. */ 8930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.this.colour_type == 0 || d.this.colour_type == 4) 8931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (d.this.bit_depth) 8933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 1: 8935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 2: 8938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.maxerrout > d.pm->error_gray_2) 8939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->error_gray_2 = d.maxerrout; 8940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 4: 8944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.maxerrout > d.pm->error_gray_4) 8945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->error_gray_4 = d.maxerrout; 8946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 8: 8950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.maxerrout > d.pm->error_gray_8) 8951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->error_gray_8 = d.maxerrout; 8952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 16: 8956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.maxerrout > d.pm->error_gray_16) 8957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->error_gray_16 = d.maxerrout; 8958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 8962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "bad bit depth (internal: 1)"); 8963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (d.this.colour_type == 2 || d.this.colour_type == 6) 8967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (d.this.bit_depth) 8969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 8: 8971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.maxerrout > d.pm->error_color_8) 8973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->error_color_8 = d.maxerrout; 8974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case 16: 8978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.maxerrout > d.pm->error_color_16) 8980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->error_color_16 = d.maxerrout; 8981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 8983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 8985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_error(pp, "bad bit depth (internal: 2)"); 8986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (d.this.colour_type == 3) 8990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 8991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (d.maxerrout > d.pm->error_indexed) 8992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik d.pm->error_indexed = d.maxerrout; 8993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 8995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 8996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch(fault) 8997b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari modifier_reset(voidcast(png_modifier*,(void*)fault)); 8998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 8999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9000b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void gamma_threshold_test(png_modifier *pm, png_byte colour_type, 9001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth, int interlace_type, double file_gamma, 9002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double screen_gamma) 9003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 9005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[64]; 9006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "threshold "); 9007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(name, sizeof name, pos, file_gamma, 3); 9008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "/"); 9009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(name, sizeof name, pos, screen_gamma, 3); 9010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (void)gamma_test(pm, colour_type, bit_depth, 0/*palette*/, interlace_type, 9012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik file_gamma, screen_gamma, 0/*sBIT*/, 1/*threshold test*/, name, 9013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0 /*no input precision*/, 9014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0 /*no scale16*/, 0 /*no expand16*/, 0 /*no background*/, 0 /*hence*/, 9015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0 /*no background gamma*/); 9016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9018b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 9019b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_gamma_threshold_tests(png_modifier *pm) 9020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type = 0; 9022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth = 0; 9023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int palette_number = 0; 9024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Don't test more than one instance of each palette - it's pointless, in 9026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * fact this test is somewhat excessive since libpng doesn't make this 9027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * decision based on colour type or bit depth! 9028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9029b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) 9030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (palette_number == 0) 9031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double test_gamma = 1.0; 9033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (test_gamma >= .4) 9034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* There's little point testing the interlacing vs non-interlacing, 9036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * but this can be set from the command line. 9037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_threshold_test(pm, colour_type, bit_depth, pm->interlace_type, 9039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_gamma, 1/test_gamma); 9040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik test_gamma *= .95; 9041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And a special test for sRGB */ 9044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_threshold_test(pm, colour_type, bit_depth, pm->interlace_type, 9045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik .45455, 2.2); 9046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9052b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void gamma_transform_test(png_modifier *pm, 9053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth, 9054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int palette_number, 9055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int interlace_type, PNG_CONST double file_gamma, 9056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double screen_gamma, PNG_CONST png_byte sbit, 9057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int use_input_precision, PNG_CONST int scale16) 9058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 9060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[64]; 9061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (sbit != bit_depth && sbit != 0) 9063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "sbit("); 9065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(name, sizeof name, pos, sbit); 9066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, ") "); 9067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 9070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "gamma "); 9071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (scale16) 9073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "16to8 "); 9074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(name, sizeof name, pos, file_gamma, 3); 9076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "->"); 9077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(name, sizeof name, pos, screen_gamma, 3); 9078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type, 9080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik file_gamma, screen_gamma, sbit, 0, name, use_input_precision, 9081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik scale16, pm->test_gamma_expand16, 0 , 0, 0); 9082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9084b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void perform_gamma_transform_tests(png_modifier *pm) 9085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type = 0; 9087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth = 0; 9088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int palette_number = 0; 9089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9090b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) 9091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int i, j; 9093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<pm->ngamma_tests; ++i) for (j=0; j<pm->ngamma_tests; ++j) 9095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (i != j) 9096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_transform_test(pm, colour_type, bit_depth, palette_number, 9098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 0/*sBIT*/, 9099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision, 0 /*do not scale16*/); 9100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9107b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void perform_gamma_sbit_tests(png_modifier *pm) 9108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte sbit; 9110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The only interesting cases are colour and grayscale, alpha is ignored here 9112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * for overall speed. Only bit depths where sbit is less than the bit depth 9113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * are tested. 9114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (sbit=pm->sbitlow; sbit<(1<<READ_BDHI); ++sbit) 9116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type = 0, bit_depth = 0; 9118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int npalette = 0; 9119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9120b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (next_format(&colour_type, &bit_depth, &npalette, 1/*gamma*/)) 9121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((colour_type & PNG_COLOR_MASK_ALPHA) == 0 && 9122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ((colour_type == 3 && sbit < 8) || 9123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (colour_type != 3 && sbit < bit_depth))) 9124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int i; 9126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<pm->ngamma_tests; ++i) 9128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int j; 9130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (j=0; j<pm->ngamma_tests; ++j) if (i != j) 9132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_transform_test(pm, colour_type, bit_depth, npalette, 9134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 9135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sbit, pm->use_input_precision_sbit, 0 /*scale16*/); 9136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Note that this requires a 16 bit source image but produces 8 bit output, so 9146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * we only need the 16bit write support, but the 16 bit images are only 9147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * generated if DO_16BIT is defined. 9148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef DO_16BIT 9150b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void perform_gamma_scale16_tests(png_modifier *pm) 9151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifndef PNG_MAX_GAMMA_8 9153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# define PNG_MAX_GAMMA_8 11 9154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 9155b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# define SBIT_16_TO_8 PNG_MAX_GAMMA_8 9156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Include the alpha cases here. Note that sbit matches the internal value 9157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * used by the library - otherwise we will get spurious errors from the 9158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * internal sbit style approximation. 9159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 9160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The threshold test is here because otherwise the 16 to 8 conversion will 9161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * proceed *without* gamma correction, and the tests above will fail (but not 9162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * by much) - this could be fixed, it only appears with the -g option. 9163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int i, j; 9165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<pm->ngamma_tests; ++i) 9166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (j=0; j<pm->ngamma_tests; ++j) 9168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (i != j && 9170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD) 9171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_transform_test(pm, 0, 16, 0, pm->interlace_type, 9173b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, 9174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision_16to8, 1 /*scale16*/); 9175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_transform_test(pm, 2, 16, 0, pm->interlace_type, 9180b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, 9181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision_16to8, 1 /*scale16*/); 9182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_transform_test(pm, 4, 16, 0, pm->interlace_type, 9187b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, 9188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision_16to8, 1 /*scale16*/); 9189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_transform_test(pm, 6, 16, 0, pm->interlace_type, 9194b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 1/pm->gammas[i], pm->gammas[j], SBIT_16_TO_8, 9195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision_16to8, 1 /*scale16*/); 9196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* 16 to 8 bit conversion */ 9204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ 9206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik defined(PNG_READ_ALPHA_MODE_SUPPORTED) 9207b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void gamma_composition_test(png_modifier *pm, 9208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth, 9209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int palette_number, 9210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int interlace_type, PNG_CONST double file_gamma, 9211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST double screen_gamma, 9212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int use_input_precision, PNG_CONST int do_background, 9213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST int expand_16) 9214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 9216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_const_charp base; 9217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double bg; 9218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char name[128]; 9219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_color_16 background; 9220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Make up a name and get an appropriate background gamma value. */ 9222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (do_background) 9223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 9225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = ""; 9226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = 4; /* should not be used */ 9227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_SCREEN: 9229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = " bckg(Screen):"; 9230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = 1/screen_gamma; 9231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_FILE: 9233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = " bckg(File):"; 9234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = file_gamma; 9235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case PNG_BACKGROUND_GAMMA_UNIQUE: 9237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = " bckg(Unique):"; 9238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This tests the handling of a unique value, the math is such that the 9239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value tends to be <1, but is neither screen nor file (even if they 9240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * match!) 9241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = (file_gamma + screen_gamma) / 3; 9243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_ALPHA_MODE_SUPPORTED 9245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_PNG: 9246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = " alpha(PNG)"; 9247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = 4; /* should not be used */ 9248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD: 9250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = " alpha(Porter-Duff)"; 9251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = 4; /* should not be used */ 9252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED: 9254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = " alpha(Optimized)"; 9255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = 4; /* should not be used */ 9256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN: 9258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = " alpha(Broken)"; 9259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik bg = 4; /* should not be used */ 9260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 9262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Use random background values - the background is always presented in the 9265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * output space (8 or 16 bit components). 9266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (expand_16 || bit_depth == 16) 9268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 r = random_32(); 9270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.red = (png_uint_16)r; 9272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.green = (png_uint_16)(r >> 16); 9273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik r = random_32(); 9274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.blue = (png_uint_16)r; 9275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.gray = (png_uint_16)(r >> 16); 9276b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9277b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* In earlier libpng versions, those where DIGITIZE is set, any background 9278b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * gamma correction in the expand16 case was done using 8-bit gamma 9279b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * correction tables, resulting in larger errors. To cope with those 9280b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * cases use a 16-bit background value which will handle this gamma 9281b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * correction. 9282b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 9283b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# if DIGITIZE 9284b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (expand_16 && (do_background == PNG_BACKGROUND_GAMMA_UNIQUE || 9285b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari do_background == PNG_BACKGROUND_GAMMA_FILE) && 9286b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fabs(bg*screen_gamma-1) > PNG_GAMMA_THRESHOLD) 9287b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 9288b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* The background values will be looked up in an 8-bit table to do 9289b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * the gamma correction, so only select values which are an exact 9290b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * match for the 8-bit table entries: 9291b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 9292b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari background.red = (png_uint_16)((background.red >> 8) * 257); 9293b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari background.green = (png_uint_16)((background.green >> 8) * 257); 9294b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari background.blue = (png_uint_16)((background.blue >> 8) * 257); 9295b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari background.gray = (png_uint_16)((background.gray >> 8) * 257); 9296b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 9297b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 9298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else /* 8 bit colors */ 9301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 r = random_32(); 9303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.red = (png_byte)r; 9305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.green = (png_byte)(r >> 8); 9306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.blue = (png_byte)(r >> 16); 9307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.gray = (png_byte)(r >> 24); 9308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.index = 193; /* rgb(193,193,193) to detect errors */ 9311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!(colour_type & PNG_COLOR_MASK_COLOR)) 9312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Grayscale input, we do not convert to RGB (TBD), so we must set the 9314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * background to gray - else libpng seems to fail. 9315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik background.red = background.green = background.blue = background.gray; 9317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "gamma "); 9320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(name, sizeof name, pos, file_gamma, 3); 9321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "->"); 9322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(name, sizeof name, pos, screen_gamma, 3); 9323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, base); 9325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (do_background < ALPHA_MODE_OFFSET) 9326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Include the background color and gamma in the name: */ 9328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, "("); 9329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This assumes no expand gray->rgb - the current code won't handle that! 9330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (colour_type & PNG_COLOR_MASK_COLOR) 9332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(name, sizeof name, pos, background.red); 9334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, ","); 9335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(name, sizeof name, pos, background.green); 9336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, ","); 9337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(name, sizeof name, pos, background.blue); 9338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 9340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(name, sizeof name, pos, background.gray); 9341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(name, sizeof name, pos, ")^"); 9342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatd(name, sizeof name, pos, bg, 3); 9343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type, 9346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik file_gamma, screen_gamma, 0/*sBIT*/, 0, name, use_input_precision, 9347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 0/*strip 16*/, expand_16, do_background, &background, bg); 9348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9351b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 9352b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_gamma_composition_tests(png_modifier *pm, int do_background, 9353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int expand_16) 9354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte colour_type = 0; 9356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_byte bit_depth = 0; 9357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int palette_number = 0; 9358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Skip the non-alpha cases - there is no setting of a transparency colour at 9360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * present. 9361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9362b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari while (next_format(&colour_type, &bit_depth, &palette_number, 1/*gamma*/)) 9363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0) 9364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int i, j; 9366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Don't skip the i==j case here - it's relevant. */ 9368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (i=0; i<pm->ngamma_tests; ++i) for (j=0; j<pm->ngamma_tests; ++j) 9369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gamma_composition_test(pm, colour_type, bit_depth, palette_number, 9371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 9372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->use_input_precision, do_background, expand_16); 9373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ 9380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9381b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 9382b50c217251b086440efcdb273c22f86a06c80cbaChris Craikinit_gamma_errors(png_modifier *pm) 9383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9384b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Use -1 to catch tests that were not actually run */ 9385b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = -1.; 9386b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->error_color_8 = -1.; 9387b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->error_indexed = -1.; 9388b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->error_gray_16 = pm->error_color_16 = -1.; 9389b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari} 9390b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9391b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void 9392b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariprint_one(const char *leader, double err) 9393b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{ 9394b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (err != -1.) 9395b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari printf(" %s %.5f\n", leader, err); 9396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9398b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 9399b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarisummarize_gamma_errors(png_modifier *pm, png_const_charp who, int low_bit_depth, 9400b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari int indexed) 9401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9402b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fflush(stderr); 9403b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (who) 9405b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari printf("\nGamma correction with %s:\n", who); 9406b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9407b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 9408b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari printf("\nBasic gamma correction:\n"); 9409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (low_bit_depth) 9411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9412b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari print_one(" 2 bit gray: ", pm->error_gray_2); 9413b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari print_one(" 4 bit gray: ", pm->error_gray_4); 9414b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari print_one(" 8 bit gray: ", pm->error_gray_8); 9415b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari print_one(" 8 bit color:", pm->error_color_8); 9416b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (indexed) 9417b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari print_one(" indexed: ", pm->error_indexed); 9418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9420b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari print_one("16 bit gray: ", pm->error_gray_16); 9421b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari print_one("16 bit color:", pm->error_color_16); 9422b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9423b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fflush(stdout); 9424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9426b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 9427b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_gamma_test(png_modifier *pm, int summary) 9428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /*TODO: remove this*/ 9430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Save certain values for the temporary overrides below. */ 9431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int calculations_use_input_precision = 9432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->calculations_use_input_precision; 9433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_BACKGROUND_SUPPORTED 9434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik double maxout8 = pm->maxout8; 9435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 9436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* First some arbitrary no-transform tests: */ 9438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!pm->this.speed && pm->test_gamma_threshold) 9439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_gamma_threshold_tests(pm); 9441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fail(pm)) 9443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return; 9444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now some real transforms. */ 9447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_gamma_transform) 9448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (summary) 9450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9451b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fflush(stderr); 9452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("Gamma correction error summary\n\n"); 9453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("The printed value is the maximum error in the pixel values\n"); 9454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("calculated by the libpng gamma correction code. The error\n"); 9455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("is calculated as the difference between the output pixel\n"); 9456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("value (always an integer) and the ideal value from the\n"); 9457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("libpng specification (typically not an integer).\n\n"); 9458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("Expect this value to be less than .5 for 8 bit formats,\n"); 9460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("less than 1 for formats with fewer than 8 bits and a small\n"); 9461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("number (typically less than 5) for the 16 bit formats.\n"); 9462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("For performance reasons the value for 16 bit formats\n"); 9463b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari printf("increases when the image file includes an sBIT chunk.\n"); 9464b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fflush(stdout); 9465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9466b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9467b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari init_gamma_errors(pm); 9468b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /*TODO: remove this. Necessary because the current libpng 9469b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * implementation works in 8 bits: 9470b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 9471b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (pm->test_gamma_expand16) 9472b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->calculations_use_input_precision = 1; 9473b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari perform_gamma_transform_tests(pm); 9474b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (!calculations_use_input_precision) 9475b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm->calculations_use_input_precision = 0; 9476b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9477b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (summary) 9478b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari summarize_gamma_errors(pm, 0/*who*/, 1/*low bit depth*/, 1/*indexed*/); 9479b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9480b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (fail(pm)) 9481b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return; 9482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The sbit tests produce much larger errors: */ 9485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_gamma_sbit) 9486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_gamma_errors(pm); 9488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_gamma_sbit_tests(pm); 9489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (summary) 9491b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari summarize_gamma_errors(pm, "sBIT", pm->sbitlow < 8U, 1/*indexed*/); 9492b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9493b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (fail(pm)) 9494b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return; 9495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef DO_16BIT /* Should be READ_16BIT_SUPPORTED */ 9498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_gamma_scale16) 9499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The 16 to 8 bit strip operations: */ 9501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_gamma_errors(pm); 9502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_gamma_scale16_tests(pm); 9503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (summary) 9505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9506b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fflush(stderr); 9507b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari printf("\nGamma correction with 16 to 8 bit reduction:\n"); 9508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf(" 16 bit gray: %.5f\n", pm->error_gray_16); 9509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf(" 16 bit color: %.5f\n", pm->error_color_16); 9510b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fflush(stdout); 9511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9512b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9513b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (fail(pm)) 9514b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return; 9515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 9517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_BACKGROUND_SUPPORTED 9519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_gamma_background) 9520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_gamma_errors(pm); 9522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /*TODO: remove this. Necessary because the current libpng 9524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * implementation works in 8 bits: 9525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_gamma_expand16) 9527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->calculations_use_input_precision = 1; 9529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->maxout8 = .499; /* because the 16 bit background is smashed */ 9530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_gamma_composition_tests(pm, PNG_BACKGROUND_GAMMA_UNIQUE, 9532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_expand16); 9533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!calculations_use_input_precision) 9534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->calculations_use_input_precision = 0; 9535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->maxout8 = maxout8; 9536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (summary) 9538b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari summarize_gamma_errors(pm, "background", 1, 0/*indexed*/); 9539b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9540b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (fail(pm)) 9541b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return; 9542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 9544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_ALPHA_MODE_SUPPORTED 9546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_gamma_alpha_mode) 9547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int do_background; 9549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik init_gamma_errors(pm); 9551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /*TODO: remove this. Necessary because the current libpng 9553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * implementation works in 8 bits: 9554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm->test_gamma_expand16) 9556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->calculations_use_input_precision = 1; 9557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (do_background = ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD; 9558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik do_background <= ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN && !fail(pm); 9559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++do_background) 9560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_gamma_composition_tests(pm, do_background, 9561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->test_gamma_expand16); 9562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!calculations_use_input_precision) 9563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm->calculations_use_input_precision = 0; 9564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (summary) 9566b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari summarize_gamma_errors(pm, "alpha mode", 1, 0/*indexed*/); 9567b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 9568b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (fail(pm)) 9569b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return; 9570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 9572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_GAMMA_SUPPORTED */ 9574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_SUPPORTED */ 9575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* INTERLACE MACRO VALIDATION */ 9577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This is copied verbatim from the specification, it is simply the pass 9578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * number in which each pixel in each 8x8 tile appears. The array must 9579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * be indexed adam7[y][x] and notice that the pass numbers are based at 9580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 1, not 0 - the base libpng uses. 9581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9582b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic PNG_CONST 9583b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_byte adam7[8][8] = 9584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 1,6,4,6,2,6,4,6 }, 9586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7,7,7,7,7,7,7,7 }, 9587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5,6,5,6,5,6,5,6 }, 9588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7,7,7,7,7,7,7,7 }, 9589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 3,6,4,6,3,6,4,6 }, 9590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7,7,7,7,7,7,7,7 }, 9591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 5,6,5,6,5,6,5,6 }, 9592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 7,7,7,7,7,7,7,7 } 9593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}; 9594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This routine validates all the interlace support macros in png.h for 9596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * a variety of valid PNG widths and heights. It uses a number of similarly 9597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * named internal routines that feed off the above array. 9598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9599b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 9600b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_pass_start_row(int pass) 9601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int x, y; 9603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) 9605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return y; 9606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0xf; 9607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9609b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 9610b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_pass_start_col(int pass) 9611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int x, y; 9613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) 9615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return x; 9616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0xf; 9617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9619b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 9620b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_pass_row_shift(int pass) 9621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int x, y, base=(-1), inc=8; 9623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) 9625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (base == (-1)) 9627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = y; 9628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (base == y) 9629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik {} 9630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (inc == y-base) 9631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base=y; 9632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (inc == 8) 9633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik inc = y-base, base=y; 9634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (inc != y-base) 9635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0xff; /* error - more than one 'inc' value! */ 9636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (base == (-1)) return 0xfe; /* error - no row in pass! */ 9639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The shift is always 1, 2 or 3 - no pass has all the rows! */ 9641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (inc) 9642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9643b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 2: return 1; 9644b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 4: return 2; 9645b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 8: return 3; 9646b50c217251b086440efcdb273c22f86a06c80cbaChris Craikdefault: break; 9647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* error - unrecognized 'inc' */ 9650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (inc << 8) + 0xfd; 9651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9653b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 9654b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_pass_col_shift(int pass) 9655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int x, y, base=(-1), inc=8; 9657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) 9659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (base == (-1)) 9661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base = x; 9662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (base == x) 9663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik {} 9664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (inc == x-base) 9665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik base=x; 9666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (inc == 8) 9667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik inc = x-base, base=x; 9668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (inc != x-base) 9669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0xff; /* error - more than one 'inc' value! */ 9670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (base == (-1)) return 0xfe; /* error - no row in pass! */ 9673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The shift is always 1, 2 or 3 - no pass has all the rows! */ 9675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (inc) 9676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9677b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 1: return 0; /* pass 7 has all the columns */ 9678b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 2: return 1; 9679b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 4: return 2; 9680b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 8: return 3; 9681b50c217251b086440efcdb273c22f86a06c80cbaChris Craikdefault: break; 9682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* error - unrecognized 'inc' */ 9685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return (inc << 8) + 0xfd; 9686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9688b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 9689b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_row_from_pass_row(png_uint_32 yIn, int pass) 9690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* By examination of the array: */ 9692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (pass) 9693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9694b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 0: return yIn * 8; 9695b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 1: return yIn * 8; 9696b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 2: return yIn * 8 + 4; 9697b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 3: return yIn * 4; 9698b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 4: return yIn * 4 + 2; 9699b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 5: return yIn * 2; 9700b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 6: return yIn * 2 + 1; 9701b50c217251b086440efcdb273c22f86a06c80cbaChris Craikdefault: break; 9702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0xff; /* bad pass number */ 9705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9707b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 9708b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_col_from_pass_col(png_uint_32 xIn, int pass) 9709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* By examination of the array: */ 9711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (pass) 9712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9713b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 0: return xIn * 8; 9714b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 1: return xIn * 8 + 4; 9715b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 2: return xIn * 4; 9716b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 3: return xIn * 4 + 2; 9717b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 4: return xIn * 2; 9718b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 5: return xIn * 2 + 1; 9719b50c217251b086440efcdb273c22f86a06c80cbaChris Craikcase 6: return xIn; 9720b50c217251b086440efcdb273c22f86a06c80cbaChris Craikdefault: break; 9721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0xff; /* bad pass number */ 9724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9726b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 9727b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_row_in_interlace_pass(png_uint_32 y, int pass) 9728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Is row 'y' in pass 'pass'? */ 9730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int x; 9731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik y &= 7; 9732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (x=0; x<8; ++x) if (adam7[y][x] == pass) 9734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 9735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 9737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9739b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int 9740b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_col_in_interlace_pass(png_uint_32 x, int pass) 9741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Is column 'x' in pass 'pass'? */ 9743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int y; 9744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik x &= 7; 9745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<8; ++y) if (adam7[y][x] == pass) 9747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 1; 9748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 9750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9752b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 9753b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_pass_rows(png_uint_32 height, int pass) 9754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 tiles = height>>3; 9756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 rows = 0; 9757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int x, y; 9758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik height &= 7; 9760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass) 9762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik rows += tiles; 9764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (y < height) ++rows; 9765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; /* i.e. break the 'x', column, loop. */ 9766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return rows; 9769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9771b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32 9772b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_pass_cols(png_uint_32 width, int pass) 9773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 tiles = width>>3; 9775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 cols = 0; 9776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik unsigned int x, y; 9777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik width &= 7; 9779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pass; 9780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass) 9781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cols += tiles; 9783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (x < width) ++cols; 9784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; /* i.e. break the 'y', row, loop. */ 9785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return cols; 9788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9790b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void 9791b50c217251b086440efcdb273c22f86a06c80cbaChris Craikperform_interlace_macro_validation(void) 9792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The macros to validate, first those that depend only on pass: 9794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 9795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_PASS_START_ROW(pass) 9796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_PASS_START_COL(pass) 9797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_PASS_ROW_SHIFT(pass) 9798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_PASS_COL_SHIFT(pass) 9799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int pass; 9801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (pass=0; pass<7; ++pass) 9803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik png_uint_32 m, f, v; 9805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_PASS_START_ROW(pass); 9807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_pass_start_row(pass); 9808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_PASS_START_ROW(%d) = %u != %x\n", pass, m, f); 9811b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_PASS_START_COL(pass); 9815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_pass_start_col(pass); 9816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_PASS_START_COL(%d) = %u != %x\n", pass, m, f); 9819b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_PASS_ROW_SHIFT(pass); 9823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_pass_row_shift(pass); 9824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_PASS_ROW_SHIFT(%d) = %u != %x\n", pass, m, f); 9827b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_PASS_COL_SHIFT(pass); 9831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_pass_col_shift(pass); 9832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_PASS_COL_SHIFT(%d) = %u != %x\n", pass, m, f); 9835b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Macros that depend on the image or sub-image height too: 9839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 9840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_PASS_ROWS(height, pass) 9841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_PASS_COLS(width, pass) 9842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_ROW_FROM_PASS_ROW(yIn, pass) 9843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_COL_FROM_PASS_COL(xIn, pass) 9844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_ROW_IN_INTERLACE_PASS(y, pass) 9845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_COL_IN_INTERLACE_PASS(x, pass) 9846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik for (v=0;;) 9848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* First the base 0 stuff: */ 9850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_ROW_FROM_PASS_ROW(v, pass); 9851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_row_from_pass_row(v, pass); 9852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_ROW_FROM_PASS_ROW(%u, %d) = %u != %x\n", 9855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v, pass, m, f); 9856b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_COL_FROM_PASS_COL(v, pass); 9860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_col_from_pass_col(v, pass); 9861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_COL_FROM_PASS_COL(%u, %d) = %u != %x\n", 9864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v, pass, m, f); 9865b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_ROW_IN_INTERLACE_PASS(v, pass); 9869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_row_in_interlace_pass(v, pass); 9870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_ROW_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", 9873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v, pass, m, f); 9874b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_COL_IN_INTERLACE_PASS(v, pass); 9878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_col_in_interlace_pass(v, pass); 9879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_COL_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", 9882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v, pass, m, f); 9883b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Then the base 1 stuff: */ 9887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++v; 9888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_PASS_ROWS(v, pass); 9889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_pass_rows(v, pass); 9890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_PASS_ROWS(%u, %d) = %u != %x\n", 9893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v, pass, m, f); 9894b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik m = PNG_PASS_COLS(v, pass); 9898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik f = png_pass_cols(v, pass); 9899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (m != f) 9900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "PNG_PASS_COLS(%u, %d) = %u != %x\n", 9902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v, pass, m, f); 9903b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 9904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Move to the next v - the stepping algorithm starts skipping 9907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * values above 1024. 9908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (v > 1024) 9910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (v == PNG_UINT_31_MAX) 9912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v = (v << 1) ^ v; 9915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (v >= PNG_UINT_31_MAX) 9916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik v = PNG_UINT_31_MAX-1; 9917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 9920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 9921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Test color encodings. These values are back-calculated from the published 9923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * chromaticities. The values are accurate to about 14 decimal places; 15 are 9924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * given. These values are much more accurate than the ones given in the spec, 9925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * which typically don't exceed 4 decimal places. This allows testing of the 9926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * libpng code to its theoretical accuracy of 4 decimal places. (If pngvalid 9927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * used the published errors the 'slack' permitted would have to be +/-.5E-4 or 9928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * more.) 9929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 9930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The png_modifier code assumes that encodings[0] is sRGB and treats it 9931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * specially: do not change the first entry in this list! 9932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9933b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic PNG_CONST color_encoding test_encodings[] = 9934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* sRGB: must be first in this list! */ 9936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*gamma:*/ { 1/2.2, 9937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*red: */ { 0.412390799265959, 0.212639005871510, 0.019330818715592 }, 9938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*green:*/ { 0.357584339383878, 0.715168678767756, 0.119194779794626 }, 9939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*blue: */ { 0.180480788401834, 0.072192315360734, 0.950532152249660} }, 9940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Kodak ProPhoto (wide gamut) */ 9941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*gamma:*/ { 1/1.6 /*approximate: uses 1.8 power law compared to sRGB 2.4*/, 9942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*red: */ { 0.797760489672303, 0.288071128229293, 0.000000000000000 }, 9943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*green:*/ { 0.135185837175740, 0.711843217810102, 0.000000000000000 }, 9944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*blue: */ { 0.031349349581525, 0.000085653960605, 0.825104602510460} }, 9945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Adobe RGB (1998) */ 9946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*gamma:*/ { 1/(2+51./256), 9947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*red: */ { 0.576669042910131, 0.297344975250536, 0.027031361386412 }, 9948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*green:*/ { 0.185558237906546, 0.627363566255466, 0.070688852535827 }, 9949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*blue: */ { 0.188228646234995, 0.075291458493998, 0.991337536837639} }, 9950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Adobe Wide Gamut RGB */ 9951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*gamma:*/ { 1/(2+51./256), 9952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*red: */ { 0.716500716779386, 0.258728243040113, 0.000000000000000 }, 9953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*green:*/ { 0.101020574397477, 0.724682314948566, 0.051211818965388 }, 9954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/*blue: */ { 0.146774385252705, 0.016589442011321, 0.773892783545073} }, 9955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}; 9956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* signal handler 9958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 9959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This attempts to trap signals and escape without crashing. It needs a 9960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * context pointer so that it can throw an exception (call longjmp) to recover 9961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * from the condition; this is handled by making the png_modifier used by 'main' 9962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * into a global variable. 9963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 9964b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_modifier pm; 9965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9966b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void signal_handler(int signum) 9967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 9968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t pos = 0; 9970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char msg[64]; 9971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "caught signal: "); 9973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik switch (signum) 9975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 9976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case SIGABRT: 9977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "abort"); 9978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case SIGFPE: 9981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "floating point exception"); 9982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case SIGILL: 9985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "illegal instruction"); 9986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case SIGINT: 9989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "interrupt"); 9990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case SIGSEGV: 9993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "invalid memory access"); 9994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 9996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik case SIGTERM: 9997b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "termination request"); 9998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 9999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik default: 10001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecat(msg, sizeof msg, pos, "unknown "); 10002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pos = safecatn(msg, sizeof msg, pos, signum); 10003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik break; 10004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_log(&pm.this, NULL/*png_structp*/, msg, 1/*error*/); 10007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And finally throw an exception so we can keep going, unless this is 10009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * SIGTERM in which case stop now. 10010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (signum != SIGTERM) 10012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik struct exception_context *the_exception_context = 10014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik &pm.this.exception_context; 10015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Throw &pm.this; 10017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 10020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik exit(1); 10021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 10022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* main program */ 10024b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint main(int argc, char **argv) 10025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 10026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik volatile int summary = 1; /* Print the error summary at the end */ 10027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik volatile int memstats = 0; /* Print memory statistics at the end */ 10028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Create the given output file on success: */ 10030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik PNG_CONST char *volatile touch = NULL; 10031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This is an array of standard gamma values (believe it or not I've seen 10033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * every one of these mentioned somewhere.) 10034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 10035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * In the following list the most useful values are first! 10036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik static double 10038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik gammas[]={2.2, 1.0, 2.2/1.45, 1.8, 1.5, 2.4, 2.5, 2.62, 2.9}; 10039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* This records the command and arguments: */ 10041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik size_t cp = 0; 10042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik char command[1024]; 10043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik anon_context(&pm.this); 10045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Add appropriate signal handlers, just the ANSI specified ones: */ 10047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik signal(SIGABRT, signal_handler); 10048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik signal(SIGFPE, signal_handler); 10049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik signal(SIGILL, signal_handler); 10050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik signal(SIGINT, signal_handler); 10051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik signal(SIGSEGV, signal_handler); 10052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik signal(SIGTERM, signal_handler); 10053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef HAVE_FEENABLEEXCEPT 10055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Only required to enable FP exceptions on platforms where they start off 10056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * disabled; this is not necessary but if it is not done pngvalid will likely 10057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * end up ignoring FP conditions that other platforms fault. 10058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); 10060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 10061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik modifier_init(&pm); 10063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Preallocate the image buffer, because we know how big it needs to be, 10065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * note that, for testing purposes, it is deliberately mis-aligned by tag 10066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * bytes either side. All rows have an additional five bytes of padding for 10067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * overwrite checking. 10068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_ensure_image(&pm.this, NULL, 2, TRANSFORM_ROWMAX, TRANSFORM_HEIGHTMAX); 10070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Don't give argv[0], it's normally some horrible libtool string: */ 10072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cp = safecat(command, sizeof command, cp, "pngvalid"); 10073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Default to error on warning: */ 10075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.treat_warnings_as_errors = 1; 10076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10077b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Default assume_16_bit_calculations appropriately; this tells the checking 10078b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * code that 16-bit arithmetic is used for 8-bit samples when it would make a 10079b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * difference. 10080b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 10081b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.assume_16_bit_calculations = PNG_LIBPNG_VER >= 10700; 10082b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10083b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Currently 16 bit expansion happens at the end of the pipeline, so the 10084b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * calculations are done in the input bit depth not the output. 10085b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 10086b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * TODO: fix this 10087b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 10088b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.calculations_use_input_precision = 1U; 10089b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Store the test gammas */ 10091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.gammas = gammas; 10092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngammas = (sizeof gammas) / (sizeof gammas[0]); 10093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 0; /* default to off */ 10094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* And the test encodings */ 10096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.encodings = test_encodings; 10097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.nencodings = (sizeof test_encodings) / (sizeof test_encodings[0]); 10098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */ 10100b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* The following allows results to pass if they correspond to anything in the 10102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transformed range [input-.5,input+.5]; this is is required because of the 10103b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * way libpng treates the 16_TO_8 flag when building the gamma tables in 10104b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * releases up to 1.6.0. 10105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 10106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * TODO: review this 10107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.use_input_precision_16to8 = 1U; 10109b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.use_input_precision_sbit = 1U; /* because libpng now rounds sBIT */ 10110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Some default values (set the behavior for 'make check' here). 10112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * These values simply control the maximum error permitted in the gamma 10113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * transformations. The practial limits for human perception are described 10114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * below (the setting for maxpc16), however for 8 bit encodings it isn't 10115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * possible to meet the accepted capabilities of human vision - i.e. 8 bit 10116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * images can never be good enough, regardless of encoding. 10117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxout8 = .1; /* Arithmetic error in *encoded* value */ 10119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxabs8 = .00005; /* 1/20000 */ 10120b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.maxcalc8 = 1./255; /* +/-1 in 8 bits for compose errors */ 10121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxpc8 = .499; /* I.e., .499% fractional error */ 10122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxout16 = .499; /* Error in *encoded* value */ 10123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxabs16 = .00005;/* 1/20000 */ 10124b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.maxcalc16 =1./65535;/* +/-1 in 16 bits for compose errors */ 10125b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.maxcalcG = 1./((1<<PNG_MAX_GAMMA_8)-1); 10126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* NOTE: this is a reasonable perceptual limit. We assume that humans can 10128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * perceive light level differences of 1% over a 100:1 range, so we need to 10129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * maintain 1 in 10000 accuracy (in linear light space), which is what the 10130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * following guarantees. It also allows significantly higher errors at 10131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * higher 16 bit values, which is important for performance. The actual 10132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * maximum 16 bit error is about +/-1.9 in the fixed point implementation but 10133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * this is only allowed for values >38149 by the following: 10134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxpc16 = .005; /* I.e., 1/200% - 1/20000 */ 10136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Now parse the command line options. */ 10138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik while (--argc >= 1) 10139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int catmore = 0; /* Set if the argument has an argument. */ 10141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Record each argument for posterity: */ 10143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cp = safecat(command, sizeof command, cp, " "); 10144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cp = safecat(command, sizeof command, cp, *++argv); 10145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (strcmp(*argv, "-v") == 0) 10147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.verbose = 1; 10148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "-l") == 0) 10150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.log = 1; 10151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "-q") == 0) 10153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik summary = pm.this.verbose = pm.log = 0; 10154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "-w") == 0) 10156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.treat_warnings_as_errors = 0; 10157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--speed") == 0) 10159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.speed = 1, pm.ngamma_tests = pm.ngammas, pm.test_standard = 0, 10160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik summary = 0; 10161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--memory") == 0) 10163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik memstats = 1; 10164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--size") == 0) 10166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_size = 1; 10167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nosize") == 0) 10169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_size = 0; 10170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--standard") == 0) 10172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_standard = 1; 10173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nostandard") == 0) 10175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_standard = 0; 10176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--transform") == 0) 10178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_transform = 1; 10179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--notransform") == 0) 10181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_transform = 0; 10182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_TRANSFORMS_SUPPORTED 10184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strncmp(*argv, "--transform-disable=", 10185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sizeof "--transform-disable") == 0) 10186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_transform = 1; 10188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_disable(*argv + sizeof "--transform-disable"); 10189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strncmp(*argv, "--transform-enable=", 10192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik sizeof "--transform-enable") == 0) 10193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_transform = 1; 10195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik transform_enable(*argv + sizeof "--transform-enable"); 10196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ 10198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--gamma") == 0) 10200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Just do two gamma tests here (2.2 and linear) for speed: */ 10202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U; 10203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_threshold = 1; 10204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_transform = 1; 10205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_sbit = 1; 10206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_scale16 = 1; 10207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_background = 1; 10208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_alpha_mode = 1; 10209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nogamma") == 0) 10212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 0; 10213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--gamma-threshold") == 0) 10215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U, pm.test_gamma_threshold = 1; 10216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nogamma-threshold") == 0) 10218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_threshold = 0; 10219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--gamma-transform") == 0) 10221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U, pm.test_gamma_transform = 1; 10222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nogamma-transform") == 0) 10224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_transform = 0; 10225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--gamma-sbit") == 0) 10227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U, pm.test_gamma_sbit = 1; 10228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nogamma-sbit") == 0) 10230b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_sbit = 0; 10231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--gamma-16-to-8") == 0) 10233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U, pm.test_gamma_scale16 = 1; 10234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nogamma-16-to-8") == 0) 10236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_scale16 = 0; 10237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--gamma-background") == 0) 10239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U, pm.test_gamma_background = 1; 10240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nogamma-background") == 0) 10242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_background = 0; 10243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--gamma-alpha-mode") == 0) 10245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U, pm.test_gamma_alpha_mode = 1; 10246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--nogamma-alpha-mode") == 0) 10248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_alpha_mode = 0; 10249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--expand16") == 0) 10251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_expand16 = 1; 10252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--noexpand16") == 0) 10254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_expand16 = 0; 10255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--more-gammas") == 0) 10257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 3U; 10258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--all-gammas") == 0) 10260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = pm.ngammas; 10261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--progressive-read") == 0) 10263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.progressive = 1; 10264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--use-update-info") == 0) 10266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ++pm.use_update_info; /* Can call multiple times */ 10267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--interlace") == 0) 10269b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 10270b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# ifdef PNG_WRITE_INTERLACING_SUPPORTED 10271b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.interlace_type = PNG_INTERLACE_ADAM7; 10272b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# else 10273b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fprintf(stderr, "pngvalid: no write interlace support\n"); 10274b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return SKIP; 10275b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif 10276b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 10277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--use-input-precision") == 0) 10279b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.use_input_precision = 1U; 10280b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10281b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else if (strcmp(*argv, "--use-calculation-precision") == 0) 10282b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.use_input_precision = 0; 10283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--calculations-use-input-precision") == 0) 10285b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.calculations_use_input_precision = 1U; 10286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--assume-16-bit-calculations") == 0) 10288b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.assume_16_bit_calculations = 1U; 10289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--calculations-follow-bit-depth") == 0) 10291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.calculations_use_input_precision = 10292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.assume_16_bit_calculations = 0; 10293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--exhaustive") == 0) 10295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_exhaustive = 1; 10296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (argc > 1 && strcmp(*argv, "--sbitlow") == 0) 10298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik --argc, pm.sbitlow = (png_byte)atoi(*++argv), catmore = 1; 10299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (argc > 1 && strcmp(*argv, "--touch") == 0) 10301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik --argc, touch = *++argv, catmore = 1; 10302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (argc > 1 && strncmp(*argv, "--max", 5) == 0) 10304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik --argc; 10306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (strcmp(5+*argv, "abs8") == 0) 10308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxabs8 = atof(*++argv); 10309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(5+*argv, "abs16") == 0) 10311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxabs16 = atof(*++argv); 10312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(5+*argv, "calc8") == 0) 10314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxcalc8 = atof(*++argv); 10315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(5+*argv, "calc16") == 0) 10317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxcalc16 = atof(*++argv); 10318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(5+*argv, "out8") == 0) 10320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxout8 = atof(*++argv); 10321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(5+*argv, "out16") == 0) 10323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxout16 = atof(*++argv); 10324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(5+*argv, "pc8") == 0) 10326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxpc8 = atof(*++argv); 10327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(5+*argv, "pc16") == 0) 10329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.maxpc16 = atof(*++argv); 10330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 10332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: %s: unknown 'max' option\n", *argv); 10334b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 10335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik catmore = 1; 10338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--log8") == 0) 10341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik --argc, pm.log8 = atof(*++argv), catmore = 1; 10342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (strcmp(*argv, "--log16") == 0) 10344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik --argc, pm.log16 = atof(*++argv), catmore = 1; 10345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10346b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_SET_OPTION_SUPPORTED 10347b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else if (strncmp(*argv, "--option=", 9) == 0) 10348b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 10349b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* Syntax of the argument is <option>:{on|off} */ 10350b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari const char *arg = 9+*argv; 10351b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari unsigned char option=0, setting=0; 10352b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10353b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_ARM_NEON_API_SUPPORTED 10354b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (strncmp(arg, "arm-neon:", 9) == 0) 10355b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari option = PNG_ARM_NEON, arg += 9; 10356b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10357b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 10358b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif 10359b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_MAXIMUM_INFLATE_WINDOW 10360b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (strncmp(arg, "max-inflate-window:", 19) == 0) 10361b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari option = PNG_MAXIMUM_INFLATE_WINDOW, arg += 19; 10362b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10363b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 10364b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif 10365b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 10366b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fprintf(stderr, "pngvalid: %s: %s: unknown option\n", *argv, arg); 10367b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 10368b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 10369b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10370b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari if (strcmp(arg, "off") == 0) 10371b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari setting = PNG_OPTION_OFF; 10372b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10373b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else if (strcmp(arg, "on") == 0) 10374b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari setting = PNG_OPTION_ON; 10375b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10376b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari else 10377b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari { 10378b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fprintf(stderr, 10379b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari "pngvalid: %s: %s: unknown setting (use 'on' or 'off')\n", 10380b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *argv, arg); 10381b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 10382b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 10383b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10384b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.this.options[pm.this.noptions].option = option; 10385b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari pm.this.options[pm.this.noptions++].setting = setting; 10386b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari } 10387b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* PNG_SET_OPTION_SUPPORTED */ 10388b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari 10389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 10390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: %s: unknown argument\n", *argv); 10392b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari exit(99); 10393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (catmore) /* consumed an extra *argv */ 10396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cp = safecat(command, sizeof command, cp, " "); 10398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik cp = safecat(command, sizeof command, cp, *argv); 10399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* If pngvalid is run with no arguments default to a reasonable set of the 10403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * tests. 10404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.test_standard == 0 && pm.test_size == 0 && pm.test_transform == 0 && 10406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests == 0) 10407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Make this do all the tests done in the test shell scripts with the same 10409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * parameters, where possible. The limitation is that all the progressive 10410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * read and interlace stuff has to be done in separate runs, so only the 10411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * basic 'standard' and 'size' tests are done. 10412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_standard = 1; 10414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_size = 1; 10415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_transform = 1; 10416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.ngamma_tests = 2U; 10417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.ngamma_tests > 0 && 10420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_threshold == 0 && pm.test_gamma_transform == 0 && 10421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_sbit == 0 && pm.test_gamma_scale16 == 0 && 10422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_background == 0 && pm.test_gamma_alpha_mode == 0) 10423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_threshold = 1; 10425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_transform = 1; 10426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_sbit = 1; 10427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_scale16 = 1; 10428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_background = 1; 10429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_alpha_mode = 1; 10430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else if (pm.ngamma_tests == 0) 10433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Nothing to test so turn everything off: */ 10435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_threshold = 0; 10436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_transform = 0; 10437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_sbit = 0; 10438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_scale16 = 0; 10439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_background = 0; 10440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.test_gamma_alpha_mode = 0; 10441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Try 10444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Make useful base images */ 10446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_transform_images(&pm.this); 10447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Perform the standard and gamma tests. */ 10449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.test_standard) 10450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_interlace_macro_validation(); 10452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_formatting_test(&pm.this); 10453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_SUPPORTED 10454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_standard_test(&pm); 10455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 10456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_error_test(&pm); 10457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Various oddly sized images: */ 10460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.test_size) 10461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik make_size_images(&pm.this); 10463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# ifdef PNG_READ_SUPPORTED 10464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_size_test(&pm); 10465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik# endif 10466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_TRANSFORMS_SUPPORTED 10469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Combinatorial transforms: */ 10470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.test_transform) 10471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_transform_test(&pm); 10472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ 10473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_GAMMA_SUPPORTED 10475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.ngamma_tests > 0) 10476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik perform_gamma_test(&pm, summary); 10477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 10478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik Catch_anonymous 10481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: test aborted (probably failed in cleanup)\n"); 10483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!pm.this.verbose) 10484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.this.error[0] != 0) 10486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: first error: %s\n", pm.this.error); 10487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: run with -v to see what happened\n"); 10489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik exit(1); 10491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (summary) 10494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("%s: %s (%s point arithmetic)\n", 10496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (pm.this.nerrors || (pm.this.treat_warnings_as_errors && 10497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.nwarnings)) ? "FAIL" : "PASS", 10498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik command, 10499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || PNG_LIBPNG_VER < 10500 10500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "floating" 10501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else 10502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "fixed" 10503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 10504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik ); 10505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (memstats) 10508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik printf("Allocated memory statistics (in bytes):\n" 10510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "\tread %lu maximum single, %lu peak, %lu total\n" 10511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik "\twrite %lu maximum single, %lu peak, %lu total\n", 10512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)pm.this.read_memory_pool.max_max, 10513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)pm.this.read_memory_pool.max_limit, 10514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)pm.this.read_memory_pool.max_total, 10515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)pm.this.write_memory_pool.max_max, 10516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)pm.this.write_memory_pool.max_limit, 10517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik (unsigned long)pm.this.write_memory_pool.max_total); 10518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Do this here to provoke memory corruption errors in memory not directly 10521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * allocated by libpng - not a complete test, but better than nothing. 10522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik store_delete(&pm.this); 10524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Error exit if there are any errors, and maybe if there are any 10526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * warnings. 10527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */ 10528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (pm.this.nerrors || (pm.this.treat_warnings_as_errors && 10529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.nwarnings)) 10530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (!pm.this.verbose) 10532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: %s\n", pm.this.error); 10533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "pngvalid: %d errors, %d warnings\n", pm.this.nerrors, 10535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik pm.this.nwarnings); 10536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik exit(1); 10538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* Success case. */ 10541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (touch != NULL) 10542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik FILE *fsuccess = fopen(touch, "wt"); 10544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fsuccess != NULL) 10546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik int error = 0; 10548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(fsuccess, "PNG validation succeeded\n"); 10549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fflush(fsuccess); 10550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik error = ferror(fsuccess); 10551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik if (fclose(fsuccess) || error) 10553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "%s: write failed\n", touch); 10555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik exit(1); 10556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik else 10560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik { 10561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik fprintf(stderr, "%s: open failed\n", touch); 10562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik exit(1); 10563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik } 10565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik 10566b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari /* This is required because some very minimal configurations do not use it: 10567b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */ 10568b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari UNUSED(fail) 10569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik return 0; 10570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 10571b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else /* write or low level APIs not supported */ 10572b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint main(void) 10573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{ 10574b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari fprintf(stderr, 10575b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari "pngvalid: no low level write support in libpng, all tests skipped\n"); 10576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik /* So the test is skipped: */ 10577b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari return SKIP; 10578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} 10579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif 10580