19b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* makepng.c */
29b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define _ISOC99_SOURCE
39b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* Copyright: */
49b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define COPYRIGHT "\251 2013,2015 John Cunningham Bowler"
59b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/*
6114668651129dc978b9710d0f0ad107ee5ee3281Matt Sarett * Last changed in libpng 1.6.20 [November 24, 2015]
7ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
8ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * This code is released under the libpng license.
9ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * For conditions of distribution and use, see the disclaimer
10ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * and license in png.h
11ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
12ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Make a test PNG image.  The arguments are as follows:
13ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *    makepng [--sRGB|--linear|--1.8] [--tRNS] [--nofilters] \
159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *       color-type bit-depth [file-name]
16ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
17ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * The color-type may be numeric (and must match the numbers used by the PNG
18ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * specification) or one of the format names listed below.  The bit-depth is the
19ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * component bit depth, or the pixel bit-depth for a color-mapped image.
20ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
21ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Without any options no color-space information is written, with the options
22ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * an sRGB or the appropriate gAMA chunk is written.  "1.8" refers to the
23ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * display system used on older Apple computers to correct for high ambient
24ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * light levels in the viewing environment; it applies a transform of
25ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909
26ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * is written (1.45/2.2).
27ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
28ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * The image data is generated internally.  Unless --color is given the images
29ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * used are as follows:
30ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
31ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 1 channel: a square image with a diamond, the least luminous colors are on
32ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *    the edge of the image, the most luminous in the center.
33ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
34ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 2 channels: the color channel increases in luminosity from top to bottom, the
35ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *    alpha channel increases in opacity from left to right.
36ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
37ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 3 channels: linear combinations of, from the top-left corner clockwise,
38ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *    black, green, white, red.
39ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
40ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 4 channels: linear combinations of, from the top-left corner clockwise,
41ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *    transparent, red, green, blue.
42ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * For color-mapped images a four channel color-map is used and if --tRNS is
449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * given the PNG file has a tRNS chunk, as follows:
45ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
46ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white
47ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 2-bit: entry 0: transparent-green
48ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *        entry 1: 40%-red
49ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *        entry 2: 80%-blue
50ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *        entry 3: opaque-white
51ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 4-bit: the 16 combinations of the 2-bit case
52ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 8-bit: the 256 combinations of the 4-bit case
53ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
54ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * The palette always has 2^bit-depth entries and the tRNS chunk one fewer.  The
55ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * image is the 1-channel diamond, but using palette index, not luminosity.
56ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * For formats other than color-mapped ones if --tRNS is specified a tRNS chunk
589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * is generated with all channels equal to the low bits of 0x0101.
599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
60ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Image size is determined by the final pixel depth in bits, i.e. channels x
61ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * bit-depth, as follows:
62ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
63ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 8 bits or less:    64x64
64ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 16 bits:           256x256
65ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * More than 16 bits: 1024x1024
66ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * Row filtering is the libpng default but may be turned off (the 'none' filter
689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * is used on every row) with the --nofilters option.
69ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The images are not interlaced.
71ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
72ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * If file-name is given then the PNG is written to that file, else it is
73ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * written to stdout.  Notice that stdout is not supported on systems where, by
74ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * default, it assumes text output; this program makes no attempt to change the
75ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * text mode of stdout!
769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *    makepng --color=<color> ...
789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * If --color is given then the whole image has that color, color-mapped images
809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * will have exactly one palette entry and all image files with be 16x16 in
819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * size.  The color value is 1 to 4 decimal numbers as appropriate for the color
829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * type.
839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *    makepng --small ...
859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * If --small is given the images are no larger than required to include every
879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * possible pixel value for the format.
889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * For formats with pixels 8 bits or fewer in size the images consist of a
909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * single row with 2^pixel-depth pixels, one of every possible value.
919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * For formats with 16-bit pixels a 256x256 image is generated containing every
939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * possible pixel value.
949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * For larger pixel sizes a 256x256 image is generated where the first row
969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * consists of each pixel that has identical byte values throughout the pixel
979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * followed by rows where the byte values differ within the pixel.
989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * In all cases the pixel values are arranged in such a way that the SUB and UP
1009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * filters give byte sequences for maximal zlib compression.  By default (if
1019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * --nofilters is not given) the SUB filter is used on the first row and the UP
1029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * filter on all following rows.
1039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
1049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The --small option is meant to provide good test-case coverage, however the
1059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * images are not easy to examine visually.  Without the --small option the
1069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * images contain identical color values; the pixel values are adjusted
1079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * according to the gamma encoding with no gamma encoding being interpreted as
1089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * sRGB.
1099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
1109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * LICENSING
1119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * =========
1129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
1139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This code is copyright of the authors, see the COPYRIGHT define above.  The
1149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * code is licensed as above, using the libpng license.  The code generates
1159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * images which are solely the product of the code; the options choose which of
1169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the many possibilities to generate.  The images that result (but not the code
1179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * which generates them) are licensed as defined here:
1189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
1199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * IMPORTANT: the COPYRIGHT #define must contain ISO-Latin-1 characters, the
1209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * IMAGE_LICENSING #define must contain UTF-8 characters.  The 'copyright'
1219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * symbol 0xA9U (\251) in ISO-Latin-1 encoding and 0xC20xA9 (\302\251) in UTF-8.
122ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
1239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define IMAGE_LICENSING "Dedicated to the public domain per Creative Commons "\
1249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    "license \"CC0 1.0\"; https://creativecommons.org/publicdomain/zero/1.0/"
125ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
126ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <stddef.h> /* for offsetof */
127ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <stdlib.h>
128ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <stdio.h>
129ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <string.h>
130ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <ctype.h>
131ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <math.h>
132ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <errno.h>
1339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <assert.h>
1349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stdint.h>
135ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
136ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
137ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#  include <config.h>
138ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#endif
139ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
140ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* Define the following to use this test against your installed libpng, rather
141ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * than the one being built here:
142ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
143ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#ifdef PNG_FREESTANDING_TESTS
144ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#  include <png.h>
145ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#else
146ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#  include "../../png.h"
147ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#endif
148ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <zlib.h>
1509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
1519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* Work round for GCC complaints about casting a (double) function result to
1529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * an unsigned:
1539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */
1549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic unsigned int
1559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettflooru(double d)
1569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{
1579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   d = floor(d);
1589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return (unsigned int)d;
1599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}
1609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
1619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic png_byte
1629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettfloorb(double d)
1639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{
1649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   d = floor(d);
1659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return (png_byte)d;
1669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}
1679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
168ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* This structure is used for inserting extra chunks (the --insert argument, not
169ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * documented above.)
170ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
171ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craiktypedef struct chunk_insert
172ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
173ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   struct chunk_insert *next;
174ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   void               (*insert)(png_structp, png_infop, int, png_charpp);
175ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int                  nparams;
176ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_charp            parameters[1];
177ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik} chunk_insert;
178ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic unsigned int
180ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikchannels_of_type(int color_type)
181ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
182ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (color_type & PNG_COLOR_MASK_PALETTE)
183ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 1;
184ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
185ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
186ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
187ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      int channels = 1;
188ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
189ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (color_type & PNG_COLOR_MASK_COLOR)
190ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         channels = 3;
191ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
192ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (color_type & PNG_COLOR_MASK_ALPHA)
193ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return channels + 1;
194ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
195ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
196ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return channels;
197ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
198ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
199ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
2009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic unsigned int
201ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikpixel_depth_of_type(int color_type, int bit_depth)
202ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
203ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return channels_of_type(color_type) * bit_depth;
204ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
205ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
206ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic unsigned int
2079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettimage_size_of_type(int color_type, int bit_depth, unsigned int *colors,
2089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   int small)
209ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
210ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (*colors)
211ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 16;
212ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
213ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
214ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
215ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
216ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
2179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (small)
2189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
2199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (pixel_depth <= 8) /* there will be one row */
2209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            return 1 << pixel_depth;
2219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
2229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         else
2239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            return 256;
2249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
2259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
2269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      else if (pixel_depth < 8)
227ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 64;
228ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
229ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (pixel_depth > 16)
230ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1024;
231ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
232ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
233ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 256;
234ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
235ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
236ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
237ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
238ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikset_color(png_colorp color, png_bytep trans, unsigned int red,
239ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   unsigned int green, unsigned int blue, unsigned int alpha,
240ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_const_bytep gamma_table)
241ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
242ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   color->red = gamma_table[red];
243ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   color->green = gamma_table[green];
244ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   color->blue = gamma_table[blue];
245ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   *trans = (png_byte)alpha;
246ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
247ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
248ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int
249ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikgenerate_palette(png_colorp palette, png_bytep trans, int bit_depth,
250ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_const_bytep gamma_table, unsigned int *colors)
251ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
252ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /*
253ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white
254ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * 2-bit: entry 0: transparent-green
255ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    *        entry 1: 40%-red
256ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    *        entry 2: 80%-blue
257ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    *        entry 3: opaque-white
258ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * 4-bit: the 16 combinations of the 2-bit case
259ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * 8-bit: the 256 combinations of the 4-bit case
260ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
261ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   switch (colors[0])
262ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
263ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      default:
264ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "makepng: --colors=...: invalid count %u\n",
265ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            colors[0]);
266ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
267ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
268ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 1:
269ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255,
270ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            gamma_table);
271ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
272ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
273ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 2:
274ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         set_color(palette+0, trans+0, colors[1], colors[1], colors[1],
275ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            colors[2], gamma_table);
276ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
277ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
278ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 3:
279ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255,
280ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            gamma_table);
281ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
282ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
283ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 4:
284ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         set_color(palette+0, trans+0, colors[1], colors[2], colors[3],
285ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            colors[4], gamma_table);
286ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
287ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
288ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 0:
289ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (bit_depth == 1)
290ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
291ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table);
292ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table);
293ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return 2;
294ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
295ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
296ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else
297ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
298ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */
2999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            unsigned int x, y;
3009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            volatile unsigned int ip = 0;
301ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
302ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            for (x=0; x<size; ++x) for (y=0; y<size; ++y)
303ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
304ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               ip = x + (size * y);
305ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
306ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               /* size is at most 16, so the scaled value below fits in 16 bits
307ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                */
308ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#              define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2))
309ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#              define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\
310ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  (interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\
311ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  (size*size))
312ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
313ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_color(palette+ip, trans+ip,
314ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  /* color:    green, red,blue,white */
315ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  xyinterp(x, y,   0, 255,   0, 255),
316ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  xyinterp(x, y, 255,   0,   0, 255),
317ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  xyinterp(x, y,   0,   0, 255, 255),
318ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  /* alpha:        0, 102, 204, 255) */
319ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  xyinterp(x, y,   0, 102, 204, 255),
320ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  gamma_table);
321ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
322ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
323ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return ip+1;
324ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
325ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
326ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
327ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
328ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
329ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikset_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth,
330ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_uint_32 value, png_const_bytep gamma_table, double conv)
331ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
332ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   unsigned int mask = (1U << bit_depth)-1;
333ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
334ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   x *= bit_depth;  /* Maximum x is 4*1024, maximum bit_depth is 16 */
335ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
336ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (value <= mask)
337ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
338ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_uint_32 offset = x >> 3;
339ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
340ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (offset < rowbytes && (bit_depth < 16 || offset+1 < rowbytes))
341ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
342ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         row += offset;
343ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
344ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         switch (bit_depth)
345ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
346ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            case 1:
347ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            case 2:
348ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            case 4:
349ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               /* Don't gamma correct - values get smashed */
350ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               {
351ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  unsigned int shift = (8 - bit_depth) - (x & 0x7U);
352ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
353ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  mask <<= shift;
354ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  value = (value << shift) & mask;
355ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  *row = (png_byte)((*row & ~mask) | value);
356ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               }
357ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               return;
358ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
359ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            default:
360ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               fprintf(stderr, "makepng: bad bit depth (internal error)\n");
361ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               exit(1);
362ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
363ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            case 16:
3649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               value = flooru(65535*pow(value/65535.,conv)+.5);
365ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               *row++ = (png_byte)(value >> 8);
366ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               *row = (png_byte)value;
367ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               return;
368ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
369ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            case 8:
370ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               *row = gamma_table[value];
371ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               return;
372ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
373ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
374ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
375ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
376ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
377ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "makepng: row buffer overflow (internal error)\n");
378ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
379ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
380ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
381ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
382ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
383ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
384ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "makepng: component overflow (internal error)\n");
385ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
386ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
387ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
388ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
3899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int /* filter mask for row */
390ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikgenerate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
391ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int bit_depth, png_const_bytep gamma_table, double conv,
3929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   unsigned int *colors, int small)
393ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
3949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   int filters = 0; /* file *MASK*, 0 means the default, not NONE */
39506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   png_uint_32 size_max =
3969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      image_size_of_type(color_type, bit_depth, colors, small)-1;
397ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */
398ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
3999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (colors[0] == 0) if (small)
4009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   {
4019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      unsigned int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
4029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
4039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      /* For pixel depths less than 16 generate a single row containing all the
4049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       * possible pixel values.  For 16 generate all 65536 byte pair
4059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       * combinations in a 256x256 pixel array.
4069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       */
4079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      switch (pixel_depth)
4089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
4099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 1:
4109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(y == 0 && rowbytes == 1 && size_max == 1);
4119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[0] = 0x6CU; /* binary: 01101100, only top 2 bits used */
4129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            filters = PNG_FILTER_NONE;
4139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            break;
4149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
4159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 2:
4169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(y == 0 && rowbytes == 1 && size_max == 3);
4179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[0] = 0x1BU; /* binary 00011011, all bits used */
4189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            filters = PNG_FILTER_NONE;
4199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            break;
4209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
4219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 4:
4229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(y == 0 && rowbytes == 8 && size_max == 15);
4239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[0] = 0x01U;
4249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[1] = 0x23U; /* SUB gives 0x22U for all following bytes */
4259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[2] = 0x45U;
4269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[3] = 0x67U;
4279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[4] = 0x89U;
4289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[5] = 0xABU;
4299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[6] = 0xCDU;
4309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            row[7] = 0xEFU;
4319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            filters = PNG_FILTER_SUB;
4329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            break;
4339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
4349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 8:
4359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            /* The row will have all the pixel values in order starting with
4369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * '1', the SUB filter will change every byte into '1' (including
4379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * the last, which generates pixel value '0').  Since the SUB filter
4389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * has value 1 this should result in maximum compression.
4399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             */
4409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(y == 0 && rowbytes == 256 && size_max == 255);
4419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            for (;;)
4429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            {
4439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               row[size_max] = 0xFFU & (size_max+1);
4449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               if (size_max == 0)
4459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  break;
4469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               --size_max;
4479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            }
4489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            filters = PNG_FILTER_SUB;
4499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            break;
4509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
4519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 16:
4529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            /* Rows are generated such that each row has a constant difference
4539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * between the first and second byte of each pixel and so that the
4549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * difference increases by 1 at each row.  The rows start with the
4559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * first byte value of 0 and the value increases to 255 across the
4569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * row.
4579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * The difference starts at 1, so the first row is:
4599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *     0 1 1 2 2 3 3 4 ... 254 255 255 0
4619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * This means that running the SUB filter on the first row produces:
4639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *   [SUB==1] 0 1 0 1 0 1...
4659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * Then the difference is 2 on the next row, giving:
4679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *    0 2 1 3 2 4 3 5 ... 254 0 255 1
4699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * When the UP filter is run on this libpng produces:
4719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *   [UP ==2] 0 1 0 1 0 1...
4739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * And so on for all the remain rows to the final two * rows:
4759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *
4769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *    row 254: 0 255 1 0 2 1 3 2 4 3 ... 254 253 255 254
4779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             *    row 255: 0   0 1 1 2 2 3 3 4 4 ... 254 254 255 255
4789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             */
4799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(rowbytes == 512 && size_max == 255);
4809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            for (;;)
4819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            {
4829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               row[2*size_max  ] = 0xFFU & size_max;
4839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               row[2*size_max+1] = 0xFFU & (size_max+y+1);
4849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               if (size_max == 0)
4859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  break;
4869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               --size_max;
4879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            }
4889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            /* The first row must include PNG_FILTER_UP so that libpng knows we
4899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * need to keep it for the following row:
4909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             */
4919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            filters = (y == 0 ? PNG_FILTER_SUB+PNG_FILTER_UP : PNG_FILTER_UP);
4929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            break;
4939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
4949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 24:
4959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 32:
4969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 48:
4979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         case 64:
4989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            /* The rows are filled by an alogorithm similar to the above, in the
4999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * first row pixel bytes are all equal, increasing from 0 by 1 for
5009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * each pixel.  In the second row the bytes within a pixel are
5019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * incremented 1,3,5,7,... from the previous row byte.  Using an odd
5029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * number ensures all the possible byte values are used.
5039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             */
5049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(size_max == 255 && rowbytes == 256*(pixel_depth>>3));
5059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            pixel_depth >>= 3; /* now in bytes */
5069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            while (rowbytes > 0)
5079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            {
5089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               const size_t pixel_index = --rowbytes/pixel_depth;
5099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
5109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               if (y == 0)
5119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  row[rowbytes] = 0xFFU & pixel_index;
5129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
5139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               else
5149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               {
5159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  const size_t byte_offset =
5169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                     rowbytes - pixel_index * pixel_depth;
5179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
5189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  row[rowbytes] =
5199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                     0xFFU & (pixel_index + (byte_offset * 2*y) + 1);
5209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               }
5219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            }
5229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            filters = (y == 0 ? PNG_FILTER_SUB+PNG_FILTER_UP : PNG_FILTER_UP);
5239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            break;
5249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
5259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         default:
5269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(0/*NOT REACHED*/);
5279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
5289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   }
52906f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
5309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   else switch (channels_of_type(color_type))
531ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
532ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* 1 channel: a square image with a diamond, the least luminous colors are on
533ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    *    the edge of the image, the most luminous in the center.
534ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
535ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 1:
536ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
537ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 x;
538ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 base = 2*size_max - abs(2*y-size_max);
539ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
540ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            for (x=0; x<=size_max; ++x)
541ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
542ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               png_uint_32 luma = base - abs(2*x-size_max);
543ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
544ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               /* 'luma' is now in the range 0..2*size_max, we need
545ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                * 0..depth_max
546ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                */
547ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               luma = (luma*depth_max + size_max) / (2*size_max);
548ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, x, bit_depth, luma, gamma_table, conv);
549ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
550ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
551ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
552ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
553ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* 2 channels: the color channel increases in luminosity from top to bottom,
554ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    *    the alpha channel increases in opacity from left to right.
555ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
556ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 2:
557ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
558ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 alpha = (depth_max * y * 2 + size_max) / (2 * size_max);
559ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 x;
560ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
561ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            for (x=0; x<=size_max; ++x)
562ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
563ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 2*x, bit_depth,
564ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  (depth_max * x * 2 + size_max) / (2 * size_max), gamma_table,
565ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  conv);
566ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table,
567ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  conv);
568ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
569ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
570ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
571ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
572ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* 3 channels: linear combinations of, from the top-left corner clockwise,
573ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    *    black, green, white, red.
574ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
575ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 3:
576ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
577ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* x0: the black->red scale (the value of the red component) at the
578ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *     start of the row (blue and green are 0).
579ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * x1: the green->white scale (the value of the red and blue
580ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *     components at the end of the row; green is depth_max).
581ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             */
582ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max);
583ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 x;
584ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
585ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* Interpolate x/depth_max from start to end:
586ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *
587ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *        start end         difference
588ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * red:     Y    Y            0
589ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * green:   0   depth_max   depth_max
590ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * blue:    0    Y            Y
591ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             */
592ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            for (x=0; x<=size_max; ++x)
593ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
594ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 3*x+0, bit_depth, /* red */ Y,
595ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     gamma_table, conv);
596ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 3*x+1, bit_depth, /* green */
597ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  (depth_max * x * 2 + size_max) / (2 * size_max),
598ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  gamma_table, conv);
599ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 3*x+2, bit_depth, /* blue */
600ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  (Y * x * 2 + size_max) / (2 * size_max),
601ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  gamma_table, conv);
602ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
603ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
604ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
605ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
606ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* 4 channels: linear combinations of, from the top-left corner clockwise,
607ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    *    transparent, red, green, blue.
608ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
609ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case 4:
610ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
611ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* x0: the transparent->blue scale (the value of the blue and alpha
612ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *     components) at the start of the row (red and green are 0).
613ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * x1: the red->green scale (the value of the red and green
614ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *     components at the end of the row; blue is 0 and alpha is
615ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *     depth_max).
616ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             */
617ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max);
618ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_uint_32 x;
619ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
620ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* Interpolate x/depth_max from start to end:
621ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *
622ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             *        start    end       difference
623ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * red:     0   depth_max-Y depth_max-Y
624ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * green:   0       Y             Y
625ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * blue:    Y       0            -Y
626ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * alpha:   Y    depth_max  depth_max-Y
627ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             */
628ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            for (x=0; x<=size_max; ++x)
629ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
630ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 4*x+0, bit_depth, /* red */
631ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  ((depth_max-Y) * x * 2 + size_max) / (2 * size_max),
632ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  gamma_table, conv);
633ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 4*x+1, bit_depth, /* green */
634ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  (Y * x * 2 + size_max) / (2 * size_max),
635ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  gamma_table, conv);
636ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 4*x+2, bit_depth, /* blue */
637ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  Y - (Y * x * 2 + size_max) / (2 * size_max),
638ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  gamma_table, conv);
639ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               set_value(row, rowbytes, 4*x+3, bit_depth, /* alpha */
640ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  Y + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max),
641ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  gamma_table, conv);
642ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
643ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
644ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
645ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
646ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      default:
647ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "makepng: internal bad channel count\n");
648ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(2);
649ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
650ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
651ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else if (color_type & PNG_COLOR_MASK_PALETTE)
652ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
653ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Palette with fixed color: the image rows are all 0 and the image width
654ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * is 16.
655ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
656ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      memset(row, 0, rowbytes);
657ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
658ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
659ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else if (colors[0] == channels_of_type(color_type))
660ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      switch (channels_of_type(color_type))
661ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
662ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         case 1:
663ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
664ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 luma = colors[1];
665ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               png_uint_32 x;
666ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
667ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               for (x=0; x<=size_max; ++x)
668ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, x, bit_depth, luma, gamma_table,
669ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
670ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
671ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            break;
672ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
673ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         case 2:
674ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
675ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 luma = colors[1];
676ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 alpha = colors[2];
677ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               png_uint_32 x;
678ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
679ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               for (x=0; x<size_max; ++x)
680ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               {
681ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 2*x, bit_depth, luma, gamma_table,
682ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
683ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table,
684ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
685ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               }
686ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
687ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            break;
688ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
689ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         case 3:
690ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
691ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 red = colors[1];
692ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 green = colors[2];
693ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 blue = colors[3];
694ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               png_uint_32 x;
695ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
696ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               for (x=0; x<=size_max; ++x)
697ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               {
698ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 3*x+0, bit_depth, red, gamma_table,
699ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
700ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 3*x+1, bit_depth, green, gamma_table,
701ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
702ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 3*x+2, bit_depth, blue, gamma_table,
703ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
704ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               }
705ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
706ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            break;
707ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
708ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         case 4:
709ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
710ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 red = colors[1];
711ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 green = colors[2];
712ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 blue = colors[3];
713ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               const png_uint_32 alpha = colors[4];
714ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               png_uint_32 x;
715ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
716ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               for (x=0; x<=size_max; ++x)
717ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               {
718ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 4*x+0, bit_depth, red, gamma_table,
719ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
720ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 4*x+1, bit_depth, green, gamma_table,
721ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
722ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 4*x+2, bit_depth, blue, gamma_table,
723ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
724ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  set_value(row, rowbytes, 4*x+3, bit_depth, alpha, gamma_table,
725ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     conv);
726ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               }
727ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
728ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
729ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
730ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         default:
731ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "makepng: internal bad channel count\n");
732ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            exit(2);
733ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
734ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
735ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
736ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
737ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr,
738ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         "makepng: --color: count(%u) does not match channels(%u)\n",
739ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         colors[0], channels_of_type(color_type));
740ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
741ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
7429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
7439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return filters;
744ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
745ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
746ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
747ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void PNGCBAPI
748ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikmakepng_warning(png_structp png_ptr, png_const_charp message)
749ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
750ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char **ep = png_get_error_ptr(png_ptr);
751ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char *name;
752ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
753ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (ep != NULL && *ep != NULL)
754ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      name = *ep;
755ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
756ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
757ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      name = "makepng";
758ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
759ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik  fprintf(stderr, "%s: warning: %s\n", name, message);
760ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
761ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
762ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void PNGCBAPI
763ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikmakepng_error(png_structp png_ptr, png_const_charp message)
764ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
765ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   makepng_warning(png_ptr, message);
766ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_longjmp(png_ptr, 1);
767ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
768ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
769ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int /* 0 on success, else an error code */
770ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikwrite_png(const char **name, FILE *fp, int color_type, int bit_depth,
771ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   volatile png_fixed_point gamma, chunk_insert * volatile insert,
7729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   unsigned int filters, unsigned int *colors, int small, int tRNS)
773ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
774ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
775ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      name, makepng_error, makepng_warning);
776ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   volatile png_infop info_ptr = NULL;
777ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   volatile png_bytep row = NULL;
778ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
779ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (png_ptr == NULL)
780ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
781ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "makepng: OOM allocating write structure\n");
782ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 1;
783ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
784ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
785ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (setjmp(png_jmpbuf(png_ptr)))
786ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
787ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_structp nv_ptr = png_ptr;
788ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_infop nv_info = info_ptr;
789ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
790ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_ptr = NULL;
791ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      info_ptr = NULL;
792ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_destroy_write_struct(&nv_ptr, &nv_info);
793ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (row != NULL) free(row);
794ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 1;
795ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
796ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
797ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Allow benign errors so that we can write PNGs with errors */
798ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_set_benign_errors(png_ptr, 1/*allowed*/);
7999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
8009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* Max out the text compression level in an attempt to make the license
8019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * small.   If --small then do the same for the IDAT.
8029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    */
8039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (small)
8049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
8059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
8069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   png_set_text_compression_level(png_ptr, Z_BEST_COMPRESSION);
8079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
808ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_init_io(png_ptr, fp);
809ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
810ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   info_ptr = png_create_info_struct(png_ptr);
811ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (info_ptr == NULL)
812ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_error(png_ptr, "OOM allocating info structure");
813ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
814ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
8159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      const unsigned int size =
8169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         image_size_of_type(color_type, bit_depth, colors, small);
8179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      unsigned int ysize;
818ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_fixed_point real_gamma = 45455; /* For sRGB */
819ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_byte gamma_table[256];
820ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      double conv;
821ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
8229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      /* Normally images are square, but with 'small' we want to simply generate
8239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       * all the pixel values, or all that we reasonably can:
8249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       */
8259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (small)
8269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
8279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         const unsigned int pixel_depth =
8289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            pixel_depth_of_type(color_type, bit_depth);
8299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
8309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (pixel_depth <= 8U)
8319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         {
8329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(size == (1U<<pixel_depth));
8339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            ysize = 1U;
8349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         }
8359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
8369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         else
8379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         {
8389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            assert(size == 256U);
8399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            ysize = 256U;
8409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         }
8419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
8429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
8439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      else
8449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         ysize = size;
8459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
846ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* This function uses the libpng values used on read to carry extra
847ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * information about the gamma:
848ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
849ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (gamma == PNG_GAMMA_MAC_18)
850ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         gamma = 65909;
851ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
852ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (gamma > 0 && gamma < 1000)
853ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         gamma = PNG_FP_1;
854ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
855ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (gamma > 0)
856ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         real_gamma = gamma;
857ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
858ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
859ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         unsigned int i;
860ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
861ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (real_gamma == 45455) for (i=0; i<256; ++i)
862ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
863ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            gamma_table[i] = (png_byte)i;
864ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            conv = 1.;
865ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
866ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
867ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else
868ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
869ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* Convert 'i' from sRGB (45455) to real_gamma, this makes
870ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             * the images look the same regardless of the gAMA chunk.
871ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             */
872ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            conv = real_gamma;
873ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            conv /= 45455;
874ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
875ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            gamma_table[0] = 0;
876ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
877ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            for (i=1; i<255; ++i)
8789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               gamma_table[i] = floorb(pow(i/255.,conv) * 255 + .5);
879ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
880ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            gamma_table[255] = 255;
881ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
882ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
883ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
8849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_set_IHDR(png_ptr, info_ptr, size, ysize, bit_depth, color_type,
885ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
886ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
887ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (color_type & PNG_COLOR_MASK_PALETTE)
888ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
889ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         int npalette;
890ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_color palette[256];
891ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_byte trans[256];
892ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
893ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         npalette = generate_palette(palette, trans, bit_depth, gamma_table,
894ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            colors);
895ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_set_PLTE(png_ptr, info_ptr, palette, npalette);
8969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
8979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (tRNS)
8989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            png_set_tRNS(png_ptr, info_ptr, trans, npalette-1,
8999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               NULL/*transparent color*/);
900ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
901ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* Reset gamma_table to prevent the image rows being changed */
902ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         for (npalette=0; npalette<256; ++npalette)
903ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            gamma_table[npalette] = (png_byte)npalette;
904ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
905ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
9069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      else if (tRNS)
9079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
9089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         png_color_16 col;
9099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
9109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         col.red = col.green = col.blue = col.gray =
9119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            0x0101U & ((1U<<bit_depth)-1U);
9129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         col.index = 0U;
9139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         png_set_tRNS(png_ptr, info_ptr, NULL/*trans*/, 1U, &col);
9149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
9159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
916ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (gamma == PNG_DEFAULT_sRGB)
917ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
918ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
919ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (gamma > 0) /* Else don't set color space information */
920ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
921ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_set_gAMA_fixed(png_ptr, info_ptr, real_gamma);
922ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
923ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* Just use the sRGB values here. */
924ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_set_cHRM_fixed(png_ptr, info_ptr,
925ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* color      x       y */
926ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* white */ 31270, 32900,
927ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* red   */ 64000, 33000,
928ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* green */ 30000, 60000,
929ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* blue  */ 15000,  6000
930ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         );
931ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
932ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
933ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Insert extra information. */
934ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      while (insert != NULL)
935ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
936ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         insert->insert(png_ptr, info_ptr, insert->nparams, insert->parameters);
937ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         insert = insert->next;
938ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
939ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
940ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Write the file header. */
941ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_write_info(png_ptr, info_ptr);
942ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
943ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Restrict the filters */
944ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters);
945ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
946ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
9479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#        ifdef PNG_WRITE_INTERLACING_SUPPORTED
9489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            int passes = png_set_interlace_handling(png_ptr);
9499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#        else /* !WRITE_INTERLACING */
9509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            int passes = 1;
9519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#        endif /* !WRITE_INTERLACING */
952ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         int pass;
953ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
954ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
955ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         row = malloc(rowbytes);
956ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
957ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (row == NULL)
958ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_error(png_ptr, "OOM allocating row buffer");
959ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
960ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         for (pass = 0; pass < passes; ++pass)
961ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
962ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            unsigned int y;
963ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
9649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            for (y=0; y<ysize; ++y)
965ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
9669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               unsigned int row_filters =
9679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  generate_row(row, rowbytes, y, color_type, bit_depth,
9689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                        gamma_table, conv, colors, small);
9699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
9709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               if (row_filters != 0 && filters == PNG_ALL_FILTERS)
9719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, row_filters);
9729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
973ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               png_write_row(png_ptr, row);
974ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
975ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
976ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
977ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
978ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
979ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Finish writing the file. */
980ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_write_end(png_ptr, info_ptr);
981ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
982ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
983ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_structp nv_ptr = png_ptr;
984ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_infop nv_info = info_ptr;
985ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
986ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_ptr = NULL;
987ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      info_ptr = NULL;
988ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_destroy_write_struct(&nv_ptr, &nv_info);
989ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
990ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   free(row);
991ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0;
992ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
993ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
994ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
995ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic size_t
996ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikload_file(png_const_charp name, png_bytepp result)
997ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
998ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   FILE *fp = tmpfile();
999ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1000ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (fp != NULL)
1001ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1002ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      FILE *ip = fopen(name, "rb");
1003ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1004ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (ip != NULL)
1005ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1006ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         size_t total = 0;
1007ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         int ch;
1008ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1009ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         for (;;)
1010ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1011ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            ch = getc(ip);
1012ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (ch == EOF) break;
1013ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            putc(ch, fp);
1014ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            ++total;
1015ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1016ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1017ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (ferror(ip))
1018ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1019ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            perror(name);
1020ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "%s: read error\n", name);
1021ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            (void)fclose(ip);
1022ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1023ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1024ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else
1025ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1026ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            (void)fclose(ip);
1027ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1028ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (ferror(fp))
1029ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
1030ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               perror("temporary file");
1031ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               fprintf(stderr, "temporary file write error\n");
1032ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
1033ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1034ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            else
1035ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
1036ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               rewind(fp);
1037ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1038ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               if (total > 0)
1039ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               {
1040ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  /* Round up to a multiple of 4 here to allow an iCCP profile
1041ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                   * to be padded to a 4x boundary.
1042ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                   */
1043ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  png_bytep data = malloc((total+3)&~3);
1044ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1045ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  if (data != NULL)
1046ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  {
1047ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     size_t new_size = 0;
1048ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1049ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     for (;;)
1050ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     {
1051ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        ch = getc(fp);
1052ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        if (ch == EOF) break;
1053ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        data[new_size++] = (png_byte)ch;
1054ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     }
1055ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1056ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     if (ferror(fp) || new_size != total)
1057ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     {
1058ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        perror("temporary file");
1059ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        fprintf(stderr, "temporary file read error\n");
1060ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        free(data);
1061ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     }
1062ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1063ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     else
1064ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     {
1065ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        (void)fclose(fp);
1066ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        *result = data;
1067ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                        return total;
1068ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     }
1069ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  }
1070ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1071ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  else
1072ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     fprintf(stderr, "%s: out of memory loading file\n", name);
1073ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               }
1074ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1075ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               else
1076ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  fprintf(stderr, "%s: empty file\n", name);
1077ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
1078ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1079ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1080ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1081ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
1082ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1083ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         perror(name);
1084ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%s: open failed\n", name);
1085ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1086ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1087ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fclose(fp);
1088ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1089ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1090ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
1091ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "makepng: %s: could not open temporary file\n", name);
1092ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1093ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   exit(1);
1094ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0;
1095ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1096ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1097ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic png_size_t
1098ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikload_fake(png_charp param, png_bytepp profile)
1099ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1100ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   char *endptr = NULL;
11019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   uint64_t size = strtoull(param, &endptr, 0/*base*/);
1102ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1103ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* The 'fake' format is <number>*[string] */
1104ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (endptr != NULL && *endptr == '*')
1105ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1106ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      size_t len = strlen(++endptr);
1107ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      size_t result = (size_t)size;
1108ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1109ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (len == 0) len = 1; /* capture the terminating '\0' */
1110ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1111ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Now repeat that string to fill 'size' bytes. */
1112ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (result == size && (*profile = malloc(result)) != NULL)
1113ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1114ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_bytep out = *profile;
1115ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1116ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (len == 1)
1117ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            memset(out, *endptr, result);
1118ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1119ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else
1120ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1121ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            while (size >= len)
1122ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
1123ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               memcpy(out, endptr, len);
1124ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               out += len;
1125ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               size -= len;
1126ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
1127ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            memcpy(out, endptr, size);
1128ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1129ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1130ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return result;
1131ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1132ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1133ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
1134ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1135ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%s: size exceeds system limits\n", param);
1136ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
1137ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1138ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1139ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1140ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0;
1141ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1142ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1143ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1144ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikcheck_param_count(int nparams, int expect)
1145ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1146ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (nparams != expect)
1147ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1148ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "bad parameter count (internal error)\n");
1149ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1150ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1151ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1152ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1153ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1154ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikinsert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams,
1155ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_charpp params)
1156ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1157ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_bytep profile = NULL;
1158ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_uint_32 proflen = 0;
1159ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int result;
1160ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1161ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   check_param_count(nparams, 2);
1162ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1163ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   switch (params[1][0])
1164ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1165ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case '<':
1166ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1167ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_size_t filelen = load_file(params[1]+1, &profile);
1168ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (filelen > 0xfffffffc) /* Maximum profile length */
1169ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
1170ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n",
1171ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  params[1]+1, (unsigned long)filelen);
1172ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               exit(1);
1173ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
1174ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1175ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            proflen = (png_uint_32)filelen;
1176ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1177ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1178ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1179ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case '0': case '1': case '2': case '3': case '4':
1180ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case '5': case '6': case '7': case '8': case '9':
1181ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1182ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_size_t fake_len = load_fake(params[1], &profile);
1183ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1184ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (fake_len > 0) /* else a simple parameter */
1185ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
1186ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               if (fake_len > 0xffffffff) /* Maximum profile length */
1187ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               {
1188ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  fprintf(stderr,
1189ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     "%s: fake data too long (%lu) for an ICC profile\n",
1190ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                     params[1], (unsigned long)fake_len);
1191ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  exit(1);
1192ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               }
1193ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               proflen = (png_uint_32)(fake_len & ~3U);
1194ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               /* Always fix up the profile length. */
1195ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               png_save_uint_32(profile, proflen);
1196ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               break;
1197ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
1198ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1199ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1200ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      default:
1201ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "--insert iCCP \"%s\": unrecognized\n", params[1]);
1202ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "  use '<' to read a file: \"<filename\"\n");
1203ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
1204ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1205ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1206ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   result = 1;
1207ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1208ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (proflen & 3)
1209ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1210ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr,
1211ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         "makepng: --insert iCCP %s: profile length made a multiple of 4\n",
1212ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         params[1]);
1213ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1214ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* load_file allocates extra space for this padding, the ICC spec requires
1215ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * padding with zero bytes.
1216ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
1217ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      while (proflen & 3)
1218ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         profile[proflen++] = 0;
1219ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1220ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1221ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (profile != NULL && proflen > 3)
1222ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1223ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_uint_32 prof_header = png_get_uint_32(profile);
1224ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1225ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (prof_header != proflen)
1226ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1227ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "--insert iCCP %s: profile length field wrong:\n",
1228ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            params[1]);
1229ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "  actual %lu, recorded value %lu (corrected)\n",
1230ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            (unsigned long)proflen, (unsigned long)prof_header);
1231ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_save_uint_32(profile, proflen);
1232ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1233ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1234ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1235ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (result && profile != NULL && proflen >=4)
1236ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_set_iCCP(png_ptr, info_ptr, params[0], PNG_COMPRESSION_TYPE_BASE,
1237ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         profile, proflen);
1238ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1239ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (profile)
1240ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      free(profile);
1241ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1242ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (!result)
1243ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1244ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1245ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1246ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1247ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikclear_text(png_text *text, png_charp keyword)
1248ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1249ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text->compression = -1; /* none */
1250ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text->key = keyword;
1251ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text->text = NULL;
1252ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text->text_length = 0; /* libpng calculates this */
1253ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text->itxt_length = 0; /* libpng calculates this */
1254ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text->lang = NULL;
1255ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text->lang_key = NULL;
1256ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1257ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1258ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1259ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikset_text(png_structp png_ptr, png_infop info_ptr, png_textp text,
1260ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_charp param)
1261ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1262ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   switch (param[0])
1263ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1264ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case '<':
1265ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1266ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_bytep file = NULL;
1267ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1268ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            text->text_length = load_file(param+1, &file);
1269ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            text->text = (png_charp)file;
1270ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1271ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1272ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1273ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case '0': case '1': case '2': case '3': case '4':
1274ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case '5': case '6': case '7': case '8': case '9':
1275ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1276ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_bytep data = NULL;
1277ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            png_size_t fake_len = load_fake(param, &data);
1278ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1279ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (fake_len > 0) /* else a simple parameter */
1280ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
1281ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               text->text_length = fake_len;
1282ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               text->text = (png_charp)data;
1283ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               break;
1284ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
1285ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1286ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1287ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      default:
1288ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         text->text = param;
1289ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1290ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1291ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1292ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_set_text(png_ptr, info_ptr, text, 1);
1293ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1294ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (text->text != param)
1295ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      free(text->text);
1296ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1297ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1298ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1299ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikinsert_tEXt(png_structp png_ptr, png_infop info_ptr, int nparams,
1300ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_charpp params)
1301ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1302ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_text text;
1303ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1304ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   check_param_count(nparams, 2);
1305ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   clear_text(&text, params[0]);
1306ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   set_text(png_ptr, info_ptr, &text, params[1]);
1307ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1308ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1309ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1310ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikinsert_zTXt(png_structp png_ptr, png_infop info_ptr, int nparams,
1311ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_charpp params)
1312ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1313ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_text text;
1314ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1315ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   check_param_count(nparams, 2);
1316ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   clear_text(&text, params[0]);
1317ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text.compression = 0; /* deflate */
1318ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   set_text(png_ptr, info_ptr, &text, params[1]);
1319ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1320ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1321ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1322ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikinsert_iTXt(png_structp png_ptr, png_infop info_ptr, int nparams,
1323ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_charpp params)
1324ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1325ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_text text;
1326ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1327ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   check_param_count(nparams, 4);
1328ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   clear_text(&text, params[0]);
1329ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text.compression = 2; /* iTXt + deflate */
1330ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text.lang = params[1];/* language tag */
1331ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   text.lang_key = params[2]; /* translated keyword */
1332ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   set_text(png_ptr, info_ptr, &text, params[3]);
1333ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1334ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1335ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
13369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettinsert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams,
13379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_charpp params)
1338ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1339ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int i;
1340ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_uint_16 freq[256];
1341ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1342ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* libpng takes the count from the PLTE count; we don't check it here but we
1343ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * do set the array to 0 for unspecified entries.
1344ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
1345ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   memset(freq, 0, sizeof freq);
1346ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   for (i=0; i<nparams; ++i)
1347ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1348ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      char *endptr = NULL;
1349ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      unsigned long int l = strtoul(params[i], &endptr, 0/*base*/);
1350ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1351ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (params[i][0] && *endptr == 0 && l <= 65535)
1352ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         freq[i] = (png_uint_16)l;
1353ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1354ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
1355ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1356ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "hIST[%d]: %s: invalid frequency\n", i, params[i]);
1357ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
1358ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1359ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1360ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1361ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_set_hIST(png_ptr, info_ptr, freq);
1362ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1363ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
136406f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarettstatic png_byte
136506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarettbval(png_const_structrp png_ptr, png_charp param, unsigned int maxval)
136606f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett{
136706f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   char *endptr = NULL;
136806f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   unsigned long int l = strtoul(param, &endptr, 0/*base*/);
136906f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
137006f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   if (param[0] && *endptr == 0 && l <= maxval)
137106f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      return (png_byte)l;
137206f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
137306f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   else
137406f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      png_error(png_ptr, "sBIT: invalid sBIT value");
137506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett}
137606f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
137706f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarettstatic void
137806f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarettinsert_sBIT(png_structp png_ptr, png_infop info_ptr, int nparams,
137906f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      png_charpp params)
138006f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett{
138106f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   const int ct = png_get_color_type(png_ptr, info_ptr);
138206f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   const int c = (ct & PNG_COLOR_MASK_COLOR ? 3 : 1) +
138306f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      (ct & PNG_COLOR_MASK_ALPHA ? 1 : 0);
138406f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   const unsigned int maxval =
138506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      ct & PNG_COLOR_MASK_PALETTE ? 8U : png_get_bit_depth(png_ptr, info_ptr);
138606f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   png_color_8 sBIT;
138706f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
138806f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   if (nparams != c)
138906f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      png_error(png_ptr, "sBIT: incorrect parameter count");
139006f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
139106f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   if (ct & PNG_COLOR_MASK_COLOR)
139206f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   {
139306f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.red = bval(png_ptr, params[0], maxval);
139406f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.green = bval(png_ptr, params[1], maxval);
139506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.blue = bval(png_ptr, params[2], maxval);
139606f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.gray = 42;
139706f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   }
139806f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
139906f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   else
140006f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   {
140106f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.red = sBIT.green = sBIT.blue = 42;
140206f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.gray = bval(png_ptr, params[0], maxval);
140306f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   }
140406f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
140506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   if (ct & PNG_COLOR_MASK_ALPHA)
140606f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.alpha = bval(png_ptr, params[nparams-1], maxval);
140706f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
140806f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   else
140906f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      sBIT.alpha = 42;
141006f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
141106f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett   png_set_sBIT(png_ptr, info_ptr, &sBIT);
141206f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett}
141306f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
1414ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#if 0
1415ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1416ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikinsert_sPLT(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params)
1417ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1418ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, "insert sPLT: NYI\n");
1419ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1420ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#endif
1421ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1422ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int
1423ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikfind_parameters(png_const_charp what, png_charp param, png_charp *list,
1424ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int nparams)
1425ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1426ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Parameters are separated by '\n' or ':' characters, up to nparams are
1427ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * accepted (more is an error) and the number found is returned.
1428ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
1429ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int i;
1430ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   for (i=0; *param && i<nparams; ++i)
1431ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1432ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      list[i] = param;
1433ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      while (*++param) if (*param == '\n' || *param == ':')
1434ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1435ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         *param++ = 0; /* Terminate last parameter */
1436ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;        /* And start a new one. */
1437ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1438ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1439ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1440ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (*param)
1441ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1442ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "--insert %s: too many parameters (%s)\n", what, param);
1443ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1444ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1445ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1446ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   list[i] = NULL; /* terminates list */
1447ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return i; /* number of parameters filled in */
1448ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1449ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1450ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1451ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikbad_parameter_count(png_const_charp what, int nparams)
1452ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1453ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, "--insert %s: bad parameter count %d\n", what, nparams);
1454ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   exit(1);
1455ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1456ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1457ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic chunk_insert *
1458ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikmake_insert(png_const_charp what,
1459ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   void (*insert)(png_structp, png_infop, int, png_charpp),
1460ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int nparams, png_charpp list)
1461ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1462ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int i;
1463ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   chunk_insert *cip;
1464ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1465ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   cip = malloc(offsetof(chunk_insert,parameters) +
1466ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      nparams * sizeof (png_charp));
1467ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1468ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (cip == NULL)
1469ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1470ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "--insert %s: out of memory allocating %d parameters\n",
1471ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         what, nparams);
1472ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1473ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1474ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1475ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   cip->next = NULL;
1476ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   cip->insert = insert;
1477ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   cip->nparams = nparams;
1478ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   for (i=0; i<nparams; ++i)
1479ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      cip->parameters[i] = list[i];
1480ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1481ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return cip;
1482ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1483ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1484ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic chunk_insert *
1485ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikfind_insert(png_const_charp what, png_charp param)
1486ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1487ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_uint_32 chunk = 0;
1488ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_charp parameter_list[1024];
1489ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int i, nparams;
1490ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1491ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Assemble the chunk name */
1492ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   for (i=0; i<4; ++i)
1493ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1494ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      char ch = what[i];
1495ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1496ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122))
1497ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         chunk = (chunk << 8) + what[i];
1498ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1499ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
1500ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1501ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1502ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1503ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (i < 4 || what[4] != 0)
1504ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1505ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "makepng --insert \"%s\": invalid chunk name\n", what);
1506ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1507ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1508ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1509ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Assemble the parameter list. */
1510ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   nparams = find_parameters(what, param, parameter_list, 1024);
1511ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1512ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#  define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d))
1513ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1514ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   switch (chunk)
1515ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1516ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case CHUNK(105,67,67,80):  /* iCCP */
1517ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (nparams == 2)
1518ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return make_insert(what, insert_iCCP, nparams, parameter_list);
1519ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1520ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1521ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case CHUNK(116,69,88,116): /* tEXt */
1522ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (nparams == 2)
1523ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return make_insert(what, insert_tEXt, nparams, parameter_list);
1524ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1525ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1526ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case CHUNK(122,84,88,116): /* zTXt */
1527ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (nparams == 2)
1528ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return make_insert(what, insert_zTXt, nparams, parameter_list);
1529ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1530ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1531ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case CHUNK(105,84,88,116): /* iTXt */
1532ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (nparams == 4)
1533ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return make_insert(what, insert_iTXt, nparams, parameter_list);
1534ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1535ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1536ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case CHUNK(104,73,83,84):  /* hIST */
1537ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (nparams <= 256)
1538ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return make_insert(what, insert_hIST, nparams, parameter_list);
1539ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
1540ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
154106f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett      case CHUNK(115,66,73,84): /* sBIT */
154206f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett         if (nparams <= 4)
154306f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett            return make_insert(what, insert_sBIT, nparams, parameter_list);
154406f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett         break;
154506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
1546ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#if 0
1547ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      case CHUNK(115,80,76,84):  /* sPLT */
1548ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return make_insert(what, insert_sPLT, nparams, parameter_list);
1549ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#endif
1550ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1551ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      default:
1552ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "makepng --insert \"%s\": unrecognized chunk name\n",
1553ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            what);
1554ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
1555ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1556ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1557ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   bad_parameter_count(what, nparams);
1558ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return NULL;
1559ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1560ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
15619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* This is necessary because libpng expects writeable strings for things like
15629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * text chunks (maybe this should be fixed...)
15639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */
15649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic png_charp
15659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstrstash(png_const_charp foo)
15669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{
15679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* The program indicates a memory allocation error by crashing, this is by
15689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * design.
15699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    */
15709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (foo != NULL)
15719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   {
15729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_charp bar = malloc(strlen(foo)+1);
15739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return strcpy(bar, foo);
15749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   }
15759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
15769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return NULL;
15779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}
15789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
15799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic png_charp
15809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstrstash_list(const png_const_charp *text)
15819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{
15829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   size_t foo = 0;
15839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   png_charp result, bar;
15849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   const png_const_charp *line = text;
15859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
15869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   while (*line != NULL)
15879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      foo += strlen(*line++);
15889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
15899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   result = bar = malloc(foo+1);
15909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
15919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   line = text;
15929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   while (*line != NULL)
15939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   {
15949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      foo = strlen(*line);
15959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      memcpy(bar, *line++, foo);
15969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      bar += foo;
15979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   }
15989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
15999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   *bar = 0;
16009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return result;
16019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}
16029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
16039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* These are used to insert Copyright and Licence fields, they allow the text to
16049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * have \n unlike the --insert option.
16059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */
16069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic chunk_insert *
16079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettadd_tEXt(const char *key, const png_const_charp *text)
16089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{
16099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   static char what[5] = { 116, 69, 88, 116, 0 };
16109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   png_charp parameter_list[3];
16119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
16129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[0] = strstash(key);
16139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[1] = strstash_list(text);
16149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[2] = NULL;
16159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
16169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return make_insert(what, insert_tEXt, 2, parameter_list);
16179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}
16189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
16199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic chunk_insert *
16209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettadd_iTXt(const char *key, const char *language, const char *language_key,
16219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      const png_const_charp *text)
16229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{
16239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   static char what[5] = { 105, 84, 88, 116, 0 };
16249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   png_charp parameter_list[5];
16259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
16269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[0] = strstash(key);
16279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[1] = strstash(language);
16289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[2] = strstash(language_key);
16299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[3] = strstash_list(text);
16309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   parameter_list[4] = NULL;
16319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
16329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return make_insert(what, insert_iTXt, 4, parameter_list);
16339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}
16349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
1635ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* This is a not-very-good parser for a sequence of numbers (including 0).  It
1636ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * doesn't accept some apparently valid things, but it accepts all the sensible
1637ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * combinations.
1638ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
1639ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic void
1640ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikparse_color(char *arg, unsigned int *colors)
1641ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1642ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   unsigned int ncolors = 0;
1643ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1644ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (*arg && ncolors < 4)
1645ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1646ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      char *ep = arg;
1647ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1648ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      unsigned long ul = strtoul(arg, &ep, 0);
1649ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1650ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (ul > 65535)
1651ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1652ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "makepng --color=...'%s': too big\n", arg);
1653ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
1654ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1655ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1656ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (ep == arg)
1657ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1658ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg);
1659ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
1660ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1661ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1662ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (*ep) ++ep; /* skip a separator */
1663ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      arg = ep;
1664ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1665ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      colors[++ncolors] = (unsigned int)ul; /* checked above */
1666ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1667ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1668ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (*arg)
1669ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1670ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "makepng --color=...'%s': too many values\n", arg);
1671ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1672ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1673ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1674ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   *colors = ncolors;
1675ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1676ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1677ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikint
1678ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikmain(int argc, char **argv)
1679ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
1680ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   FILE *fp = stdout;
1681ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char *file_name = NULL;
1682ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int color_type = 8; /* invalid */
1683ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int bit_depth = 32; /* invalid */
16849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   int small = 0; /* make full size images */
16859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   int tRNS = 0; /* don't output a tRNS chunk */
1686ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   unsigned int colors[5];
1687ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   unsigned int filters = PNG_ALL_FILTERS;
1688ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_fixed_point gamma = 0; /* not set */
1689ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   chunk_insert *head_insert = NULL;
1690ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   chunk_insert **insert_ptr = &head_insert;
1691ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1692ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   memset(colors, 0, sizeof colors);
1693ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1694ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (--argc > 0)
1695ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1696ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      char *arg = *++argv;
1697ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
16989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (strcmp(arg, "--small") == 0)
16999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
17009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         small = 1;
17019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         continue;
17029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
17039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
17049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (strcmp(arg, "--tRNS") == 0)
17059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
17069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         tRNS = 1;
17079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         continue;
17089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
17099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
1710ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(arg, "--sRGB") == 0)
1711ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1712ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         gamma = PNG_DEFAULT_sRGB;
1713ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1714ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1715ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1716ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(arg, "--linear") == 0)
1717ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1718ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         gamma = PNG_FP_1;
1719ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1720ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1721ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1722ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(arg, "--1.8") == 0)
1723ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1724ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         gamma = PNG_GAMMA_MAC_18;
1725ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1726ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1727ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1728ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(arg, "--nofilters") == 0)
1729ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1730ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         filters = PNG_FILTER_NONE;
1731ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1732ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1733ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1734ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strncmp(arg, "--color=", 8) == 0)
1735ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1736ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          parse_color(arg+8, colors);
1737ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          continue;
1738ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1739ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1740ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (argc >= 3 && strcmp(arg, "--insert") == 0)
1741ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1742ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_const_charp what = *++argv;
1743ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_charp param = *++argv;
1744ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         chunk_insert *new_insert;
1745ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1746ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         argc -= 2;
1747ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1748ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         new_insert = find_insert(what, param);
1749ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1750ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (new_insert != NULL)
1751ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1752ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            *insert_ptr = new_insert;
1753ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            insert_ptr = &new_insert->next;
1754ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1755ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1756ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1757ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1758ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1759ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (arg[0] == '-')
1760ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1761ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "makepng: %s: invalid option\n", arg);
1762ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         exit(1);
1763ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1764ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1765ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(arg, "palette") == 0)
1766ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1767ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         color_type = PNG_COLOR_TYPE_PALETTE;
1768ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1769ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1770ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1771ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strncmp(arg, "gray", 4) == 0)
1772ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1773ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (arg[4] == 0)
1774ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1775ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            color_type = PNG_COLOR_TYPE_GRAY;
1776ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            continue;
1777ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1778ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1779ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else if (strcmp(arg+4, "a") == 0 ||
1780ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            strcmp(arg+4, "alpha") == 0 ||
1781ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            strcmp(arg+4, "-alpha") == 0)
1782ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1783ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
1784ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            continue;
1785ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1786ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1787ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1788ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strncmp(arg, "rgb", 3) == 0)
1789ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1790ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (arg[3] == 0)
1791ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1792ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            color_type = PNG_COLOR_TYPE_RGB;
1793ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            continue;
1794ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1795ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1796ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else if (strcmp(arg+3, "a") == 0 ||
1797ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            strcmp(arg+3, "alpha") == 0 ||
1798ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            strcmp(arg+3, "-alpha") == 0)
1799ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1800ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1801ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            continue;
1802ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1803ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1804ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1805ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (color_type == 8 && isdigit(arg[0]))
1806ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1807ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         color_type = atoi(arg);
1808ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (color_type < 0 || color_type > 6 || color_type == 1 ||
1809ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            color_type == 5)
1810ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1811ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "makepng: %s: not a valid color type\n", arg);
1812ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            exit(1);
1813ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1814ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1815ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1816ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1817ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1818ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (bit_depth == 32 && isdigit(arg[0]))
1819ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1820ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         bit_depth = atoi(arg);
1821ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (bit_depth <= 0 || bit_depth > 16 ||
1822ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            (bit_depth & -bit_depth) != bit_depth)
1823ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1824ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "makepng: %s: not a valid bit depth\n", arg);
1825ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            exit(1);
1826ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1827ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1828ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1829ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1830ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1831ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (argc == 1) /* It's the file name */
1832ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1833ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fp = fopen(arg, "wb");
1834ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fp == NULL)
1835ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1836ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "%s: %s: could not open\n", arg, strerror(errno));
1837ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            exit(1);
1838ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1839ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1840ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         file_name = arg;
1841ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         continue;
1842ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1843ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1844ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "makepng: %s: unknown argument\n", arg);
1845ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1846ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   } /* argument while loop */
1847ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1848ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (color_type == 8 || bit_depth == 32)
1849ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
18509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      fprintf(stderr, "usage: makepng [--small] [--sRGB|--linear|--1.8] "
1851ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         "[--color=...] color-type bit-depth [file-name]\n"
18529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         "  Make a test PNG file, by default writes to stdout.\n"
18539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         "  Other options are available, UTSL.\n");
1854ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      exit(1);
1855ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1856ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1857ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Check the colors */
1858ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1859ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      const unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U :
1860ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         (1U<<bit_depth)-1);
1861ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      unsigned int i;
1862ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1863ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (i=1; i<=colors[0]; ++i)
1864ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (colors[i] > lim)
1865ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
1866ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n",
1867ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               colors[i], lim);
1868ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            exit(1);
1869ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
1870ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1871ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
18729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* small and colors are incomparible (will probably crash if both are used at
18739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * the same time!)
18749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    */
18759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (small && colors[0] != 0)
18769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   {
18779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      fprintf(stderr, "makepng: --color --small: only one at a time!\n");
18789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      exit(1);
18799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   }
18809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
1881ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Restrict the filters for more speed to those we know are used for the
1882ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * generated images.
1883ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
18849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (filters == PNG_ALL_FILTERS && !small/*small provides defaults*/)
1885ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1886ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8)
1887ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         filters = PNG_FILTER_NONE;
1888ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1889ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (color_type & PNG_COLOR_MASK_COLOR) /* rgb */
1890ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
1891ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (bit_depth == 8)
1892ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            filters &= ~(PNG_FILTER_NONE | PNG_FILTER_AVG);
1893ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1894ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else
1895ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            filters = PNG_FILTER_SUB | PNG_FILTER_PAETH;
1896ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
1897ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1898ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else /* gray 8 or 16-bit */
1899ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         filters &= ~PNG_FILTER_NONE;
1900ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1901ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
19029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* Insert standard copyright and licence text. */
19039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   {
19049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      static png_const_charp copyright[] =
19059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
19069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         COPYRIGHT, /* ISO-Latin-1 */
19079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         NULL
19089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      };
19099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      static png_const_charp licensing[] =
19109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
19119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         IMAGE_LICENSING, /* UTF-8 */
19129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         NULL
19139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      };
19149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
19159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      chunk_insert *new_insert;
191606f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett
19179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      new_insert = add_tEXt("Copyright", copyright);
19189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (new_insert != NULL)
19199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
19209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         *insert_ptr = new_insert;
19219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         insert_ptr = &new_insert->next;
19229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
19239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
19249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      new_insert = add_iTXt("Licensing", "en", NULL, licensing);
19259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (new_insert != NULL)
19269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      {
19279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         *insert_ptr = new_insert;
19289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         insert_ptr = &new_insert->next;
19299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      }
19309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   }
19319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
1932ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
1933ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      int ret = write_png(&file_name, fp, color_type, bit_depth, gamma,
19349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         head_insert, filters, colors, small, tRNS);
1935ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1936ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (ret != 0 && file_name != NULL)
1937ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         remove(file_name);
1938ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
1939ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return ret;
1940ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
1941ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1942