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