1*a67afe4dSAndroid Build Coastguard Worker /* makepng.c */
2*a67afe4dSAndroid Build Coastguard Worker #define _ISOC99_SOURCE
3*a67afe4dSAndroid Build Coastguard Worker /* Copyright: */
4*a67afe4dSAndroid Build Coastguard Worker #define COPYRIGHT "\251 2013,2015 John Cunningham Bowler"
5*a67afe4dSAndroid Build Coastguard Worker /*
6*a67afe4dSAndroid Build Coastguard Worker * This code is released under the libpng license.
7*a67afe4dSAndroid Build Coastguard Worker * For conditions of distribution and use, see the disclaimer
8*a67afe4dSAndroid Build Coastguard Worker * and license in png.h
9*a67afe4dSAndroid Build Coastguard Worker *
10*a67afe4dSAndroid Build Coastguard Worker * Make a test PNG image. The arguments are as follows:
11*a67afe4dSAndroid Build Coastguard Worker *
12*a67afe4dSAndroid Build Coastguard Worker * makepng [--sRGB|--linear|--1.8] [--tRNS] [--nofilters] \
13*a67afe4dSAndroid Build Coastguard Worker * color-type bit-depth [file-name]
14*a67afe4dSAndroid Build Coastguard Worker *
15*a67afe4dSAndroid Build Coastguard Worker * The color-type may be numeric (and must match the numbers used by the PNG
16*a67afe4dSAndroid Build Coastguard Worker * specification) or one of the format names listed below. The bit-depth is the
17*a67afe4dSAndroid Build Coastguard Worker * component bit depth, or the pixel bit-depth for a color-mapped image.
18*a67afe4dSAndroid Build Coastguard Worker *
19*a67afe4dSAndroid Build Coastguard Worker * Without any options no color-space information is written, with the options
20*a67afe4dSAndroid Build Coastguard Worker * an sRGB or the appropriate gAMA chunk is written. "1.8" refers to the
21*a67afe4dSAndroid Build Coastguard Worker * display system used on older Apple computers to correct for high ambient
22*a67afe4dSAndroid Build Coastguard Worker * light levels in the viewing environment; it applies a transform of
23*a67afe4dSAndroid Build Coastguard Worker * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909
24*a67afe4dSAndroid Build Coastguard Worker * is written (1.45/2.2).
25*a67afe4dSAndroid Build Coastguard Worker *
26*a67afe4dSAndroid Build Coastguard Worker * The image data is generated internally. Unless --color is given the images
27*a67afe4dSAndroid Build Coastguard Worker * used are as follows:
28*a67afe4dSAndroid Build Coastguard Worker *
29*a67afe4dSAndroid Build Coastguard Worker * 1 channel: a square image with a diamond, the least luminous colors are on
30*a67afe4dSAndroid Build Coastguard Worker * the edge of the image, the most luminous in the center.
31*a67afe4dSAndroid Build Coastguard Worker *
32*a67afe4dSAndroid Build Coastguard Worker * 2 channels: the color channel increases in luminosity from top to bottom, the
33*a67afe4dSAndroid Build Coastguard Worker * alpha channel increases in opacity from left to right.
34*a67afe4dSAndroid Build Coastguard Worker *
35*a67afe4dSAndroid Build Coastguard Worker * 3 channels: linear combinations of, from the top-left corner clockwise,
36*a67afe4dSAndroid Build Coastguard Worker * black, green, white, red.
37*a67afe4dSAndroid Build Coastguard Worker *
38*a67afe4dSAndroid Build Coastguard Worker * 4 channels: linear combinations of, from the top-left corner clockwise,
39*a67afe4dSAndroid Build Coastguard Worker * transparent, red, green, blue.
40*a67afe4dSAndroid Build Coastguard Worker *
41*a67afe4dSAndroid Build Coastguard Worker * For color-mapped images a four channel color-map is used and if --tRNS is
42*a67afe4dSAndroid Build Coastguard Worker * given the PNG file has a tRNS chunk, as follows:
43*a67afe4dSAndroid Build Coastguard Worker *
44*a67afe4dSAndroid Build Coastguard Worker * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white
45*a67afe4dSAndroid Build Coastguard Worker * 2-bit: entry 0: transparent-green
46*a67afe4dSAndroid Build Coastguard Worker * entry 1: 40%-red
47*a67afe4dSAndroid Build Coastguard Worker * entry 2: 80%-blue
48*a67afe4dSAndroid Build Coastguard Worker * entry 3: opaque-white
49*a67afe4dSAndroid Build Coastguard Worker * 4-bit: the 16 combinations of the 2-bit case
50*a67afe4dSAndroid Build Coastguard Worker * 8-bit: the 256 combinations of the 4-bit case
51*a67afe4dSAndroid Build Coastguard Worker *
52*a67afe4dSAndroid Build Coastguard Worker * The palette always has 2^bit-depth entries and the tRNS chunk one fewer. The
53*a67afe4dSAndroid Build Coastguard Worker * image is the 1-channel diamond, but using palette index, not luminosity.
54*a67afe4dSAndroid Build Coastguard Worker *
55*a67afe4dSAndroid Build Coastguard Worker * For formats other than color-mapped ones if --tRNS is specified a tRNS chunk
56*a67afe4dSAndroid Build Coastguard Worker * is generated with all channels equal to the low bits of 0x0101.
57*a67afe4dSAndroid Build Coastguard Worker *
58*a67afe4dSAndroid Build Coastguard Worker * Image size is determined by the final pixel depth in bits, i.e. channels x
59*a67afe4dSAndroid Build Coastguard Worker * bit-depth, as follows:
60*a67afe4dSAndroid Build Coastguard Worker *
61*a67afe4dSAndroid Build Coastguard Worker * 8 bits or less: 64x64
62*a67afe4dSAndroid Build Coastguard Worker * 16 bits: 256x256
63*a67afe4dSAndroid Build Coastguard Worker * More than 16 bits: 1024x1024
64*a67afe4dSAndroid Build Coastguard Worker *
65*a67afe4dSAndroid Build Coastguard Worker * Row filtering is the libpng default but may be turned off (the 'none' filter
66*a67afe4dSAndroid Build Coastguard Worker * is used on every row) with the --nofilters option.
67*a67afe4dSAndroid Build Coastguard Worker *
68*a67afe4dSAndroid Build Coastguard Worker * The images are not interlaced.
69*a67afe4dSAndroid Build Coastguard Worker *
70*a67afe4dSAndroid Build Coastguard Worker * If file-name is given then the PNG is written to that file, else it is
71*a67afe4dSAndroid Build Coastguard Worker * written to stdout. Notice that stdout is not supported on systems where, by
72*a67afe4dSAndroid Build Coastguard Worker * default, it assumes text output; this program makes no attempt to change the
73*a67afe4dSAndroid Build Coastguard Worker * text mode of stdout!
74*a67afe4dSAndroid Build Coastguard Worker *
75*a67afe4dSAndroid Build Coastguard Worker * makepng --color=<color> ...
76*a67afe4dSAndroid Build Coastguard Worker *
77*a67afe4dSAndroid Build Coastguard Worker * If --color is given then the whole image has that color, color-mapped images
78*a67afe4dSAndroid Build Coastguard Worker * will have exactly one palette entry and all image files with be 16x16 in
79*a67afe4dSAndroid Build Coastguard Worker * size. The color value is 1 to 4 decimal numbers as appropriate for the color
80*a67afe4dSAndroid Build Coastguard Worker * type.
81*a67afe4dSAndroid Build Coastguard Worker *
82*a67afe4dSAndroid Build Coastguard Worker * makepng --small ...
83*a67afe4dSAndroid Build Coastguard Worker *
84*a67afe4dSAndroid Build Coastguard Worker * If --small is given the images are no larger than required to include every
85*a67afe4dSAndroid Build Coastguard Worker * possible pixel value for the format.
86*a67afe4dSAndroid Build Coastguard Worker *
87*a67afe4dSAndroid Build Coastguard Worker * For formats with pixels 8 bits or fewer in size the images consist of a
88*a67afe4dSAndroid Build Coastguard Worker * single row with 2^pixel-depth pixels, one of every possible value.
89*a67afe4dSAndroid Build Coastguard Worker *
90*a67afe4dSAndroid Build Coastguard Worker * For formats with 16-bit pixels a 256x256 image is generated containing every
91*a67afe4dSAndroid Build Coastguard Worker * possible pixel value.
92*a67afe4dSAndroid Build Coastguard Worker *
93*a67afe4dSAndroid Build Coastguard Worker * For larger pixel sizes a 256x256 image is generated where the first row
94*a67afe4dSAndroid Build Coastguard Worker * consists of each pixel that has identical byte values throughout the pixel
95*a67afe4dSAndroid Build Coastguard Worker * followed by rows where the byte values differ within the pixel.
96*a67afe4dSAndroid Build Coastguard Worker *
97*a67afe4dSAndroid Build Coastguard Worker * In all cases the pixel values are arranged in such a way that the SUB and UP
98*a67afe4dSAndroid Build Coastguard Worker * filters give byte sequences for maximal zlib compression. By default (if
99*a67afe4dSAndroid Build Coastguard Worker * --nofilters is not given) the SUB filter is used on the first row and the UP
100*a67afe4dSAndroid Build Coastguard Worker * filter on all following rows.
101*a67afe4dSAndroid Build Coastguard Worker *
102*a67afe4dSAndroid Build Coastguard Worker * The --small option is meant to provide good test-case coverage, however the
103*a67afe4dSAndroid Build Coastguard Worker * images are not easy to examine visually. Without the --small option the
104*a67afe4dSAndroid Build Coastguard Worker * images contain identical color values; the pixel values are adjusted
105*a67afe4dSAndroid Build Coastguard Worker * according to the gamma encoding with no gamma encoding being interpreted as
106*a67afe4dSAndroid Build Coastguard Worker * sRGB.
107*a67afe4dSAndroid Build Coastguard Worker *
108*a67afe4dSAndroid Build Coastguard Worker * LICENSING
109*a67afe4dSAndroid Build Coastguard Worker * =========
110*a67afe4dSAndroid Build Coastguard Worker *
111*a67afe4dSAndroid Build Coastguard Worker * This code is copyright of the authors, see the COPYRIGHT define above. The
112*a67afe4dSAndroid Build Coastguard Worker * code is licensed as above, using the libpng license. The code generates
113*a67afe4dSAndroid Build Coastguard Worker * images which are solely the product of the code; the options choose which of
114*a67afe4dSAndroid Build Coastguard Worker * the many possibilities to generate. The images that result (but not the code
115*a67afe4dSAndroid Build Coastguard Worker * which generates them) are licensed as defined here:
116*a67afe4dSAndroid Build Coastguard Worker *
117*a67afe4dSAndroid Build Coastguard Worker * IMPORTANT: the COPYRIGHT #define must contain ISO-Latin-1 characters, the
118*a67afe4dSAndroid Build Coastguard Worker * IMAGE_LICENSING #define must contain UTF-8 characters. The 'copyright'
119*a67afe4dSAndroid Build Coastguard Worker * symbol 0xA9U (\251) in ISO-Latin-1 encoding and 0xC20xA9 (\302\251) in UTF-8.
120*a67afe4dSAndroid Build Coastguard Worker */
121*a67afe4dSAndroid Build Coastguard Worker #define IMAGE_LICENSING "Dedicated to the public domain per Creative Commons "\
122*a67afe4dSAndroid Build Coastguard Worker "license \"CC0 1.0\"; https://creativecommons.org/publicdomain/zero/1.0/"
123*a67afe4dSAndroid Build Coastguard Worker
124*a67afe4dSAndroid Build Coastguard Worker #include <stddef.h> /* for offsetof */
125*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
126*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
127*a67afe4dSAndroid Build Coastguard Worker #include <string.h>
128*a67afe4dSAndroid Build Coastguard Worker #include <ctype.h>
129*a67afe4dSAndroid Build Coastguard Worker #include <math.h>
130*a67afe4dSAndroid Build Coastguard Worker #include <errno.h>
131*a67afe4dSAndroid Build Coastguard Worker #include <assert.h>
132*a67afe4dSAndroid Build Coastguard Worker #include <stdint.h>
133*a67afe4dSAndroid Build Coastguard Worker
134*a67afe4dSAndroid Build Coastguard Worker #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
135*a67afe4dSAndroid Build Coastguard Worker # include <config.h>
136*a67afe4dSAndroid Build Coastguard Worker #endif
137*a67afe4dSAndroid Build Coastguard Worker
138*a67afe4dSAndroid Build Coastguard Worker /* Define the following to use this test against your installed libpng, rather
139*a67afe4dSAndroid Build Coastguard Worker * than the one being built here:
140*a67afe4dSAndroid Build Coastguard Worker */
141*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_FREESTANDING_TESTS
142*a67afe4dSAndroid Build Coastguard Worker # include <png.h>
143*a67afe4dSAndroid Build Coastguard Worker #else
144*a67afe4dSAndroid Build Coastguard Worker # include "../../png.h"
145*a67afe4dSAndroid Build Coastguard Worker #endif
146*a67afe4dSAndroid Build Coastguard Worker
147*a67afe4dSAndroid Build Coastguard Worker #include <zlib.h>
148*a67afe4dSAndroid Build Coastguard Worker
149*a67afe4dSAndroid Build Coastguard Worker /* Work round for GCC complaints about casting a (double) function result to
150*a67afe4dSAndroid Build Coastguard Worker * an unsigned:
151*a67afe4dSAndroid Build Coastguard Worker */
152*a67afe4dSAndroid Build Coastguard Worker static unsigned int
flooru(double d)153*a67afe4dSAndroid Build Coastguard Worker flooru(double d)
154*a67afe4dSAndroid Build Coastguard Worker {
155*a67afe4dSAndroid Build Coastguard Worker d = floor(d);
156*a67afe4dSAndroid Build Coastguard Worker return (unsigned int)d;
157*a67afe4dSAndroid Build Coastguard Worker }
158*a67afe4dSAndroid Build Coastguard Worker
159*a67afe4dSAndroid Build Coastguard Worker static png_byte
floorb(double d)160*a67afe4dSAndroid Build Coastguard Worker floorb(double d)
161*a67afe4dSAndroid Build Coastguard Worker {
162*a67afe4dSAndroid Build Coastguard Worker d = floor(d);
163*a67afe4dSAndroid Build Coastguard Worker return (png_byte)d;
164*a67afe4dSAndroid Build Coastguard Worker }
165*a67afe4dSAndroid Build Coastguard Worker
166*a67afe4dSAndroid Build Coastguard Worker /* This structure is used for inserting extra chunks (the --insert argument, not
167*a67afe4dSAndroid Build Coastguard Worker * documented above.)
168*a67afe4dSAndroid Build Coastguard Worker */
169*a67afe4dSAndroid Build Coastguard Worker typedef struct chunk_insert
170*a67afe4dSAndroid Build Coastguard Worker {
171*a67afe4dSAndroid Build Coastguard Worker struct chunk_insert *next;
172*a67afe4dSAndroid Build Coastguard Worker void (*insert)(png_structp, png_infop, int, png_charpp);
173*a67afe4dSAndroid Build Coastguard Worker int nparams;
174*a67afe4dSAndroid Build Coastguard Worker png_charp parameters[1];
175*a67afe4dSAndroid Build Coastguard Worker } chunk_insert;
176*a67afe4dSAndroid Build Coastguard Worker
177*a67afe4dSAndroid Build Coastguard Worker static unsigned int
channels_of_type(int color_type)178*a67afe4dSAndroid Build Coastguard Worker channels_of_type(int color_type)
179*a67afe4dSAndroid Build Coastguard Worker {
180*a67afe4dSAndroid Build Coastguard Worker if (color_type & PNG_COLOR_MASK_PALETTE)
181*a67afe4dSAndroid Build Coastguard Worker return 1;
182*a67afe4dSAndroid Build Coastguard Worker
183*a67afe4dSAndroid Build Coastguard Worker else
184*a67afe4dSAndroid Build Coastguard Worker {
185*a67afe4dSAndroid Build Coastguard Worker int channels = 1;
186*a67afe4dSAndroid Build Coastguard Worker
187*a67afe4dSAndroid Build Coastguard Worker if (color_type & PNG_COLOR_MASK_COLOR)
188*a67afe4dSAndroid Build Coastguard Worker channels = 3;
189*a67afe4dSAndroid Build Coastguard Worker
190*a67afe4dSAndroid Build Coastguard Worker if (color_type & PNG_COLOR_MASK_ALPHA)
191*a67afe4dSAndroid Build Coastguard Worker return channels + 1;
192*a67afe4dSAndroid Build Coastguard Worker
193*a67afe4dSAndroid Build Coastguard Worker else
194*a67afe4dSAndroid Build Coastguard Worker return channels;
195*a67afe4dSAndroid Build Coastguard Worker }
196*a67afe4dSAndroid Build Coastguard Worker }
197*a67afe4dSAndroid Build Coastguard Worker
198*a67afe4dSAndroid Build Coastguard Worker static unsigned int
pixel_depth_of_type(int color_type,int bit_depth)199*a67afe4dSAndroid Build Coastguard Worker pixel_depth_of_type(int color_type, int bit_depth)
200*a67afe4dSAndroid Build Coastguard Worker {
201*a67afe4dSAndroid Build Coastguard Worker return channels_of_type(color_type) * bit_depth;
202*a67afe4dSAndroid Build Coastguard Worker }
203*a67afe4dSAndroid Build Coastguard Worker
204*a67afe4dSAndroid Build Coastguard Worker static unsigned int
image_size_of_type(int color_type,int bit_depth,unsigned int * colors,int small)205*a67afe4dSAndroid Build Coastguard Worker image_size_of_type(int color_type, int bit_depth, unsigned int *colors,
206*a67afe4dSAndroid Build Coastguard Worker int small)
207*a67afe4dSAndroid Build Coastguard Worker {
208*a67afe4dSAndroid Build Coastguard Worker if (*colors)
209*a67afe4dSAndroid Build Coastguard Worker return 16;
210*a67afe4dSAndroid Build Coastguard Worker
211*a67afe4dSAndroid Build Coastguard Worker else
212*a67afe4dSAndroid Build Coastguard Worker {
213*a67afe4dSAndroid Build Coastguard Worker int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
214*a67afe4dSAndroid Build Coastguard Worker
215*a67afe4dSAndroid Build Coastguard Worker if (small)
216*a67afe4dSAndroid Build Coastguard Worker {
217*a67afe4dSAndroid Build Coastguard Worker if (pixel_depth <= 8) /* there will be one row */
218*a67afe4dSAndroid Build Coastguard Worker return 1 << pixel_depth;
219*a67afe4dSAndroid Build Coastguard Worker
220*a67afe4dSAndroid Build Coastguard Worker else
221*a67afe4dSAndroid Build Coastguard Worker return 256;
222*a67afe4dSAndroid Build Coastguard Worker }
223*a67afe4dSAndroid Build Coastguard Worker
224*a67afe4dSAndroid Build Coastguard Worker else if (pixel_depth < 8)
225*a67afe4dSAndroid Build Coastguard Worker return 64;
226*a67afe4dSAndroid Build Coastguard Worker
227*a67afe4dSAndroid Build Coastguard Worker else if (pixel_depth > 16)
228*a67afe4dSAndroid Build Coastguard Worker return 1024;
229*a67afe4dSAndroid Build Coastguard Worker
230*a67afe4dSAndroid Build Coastguard Worker else
231*a67afe4dSAndroid Build Coastguard Worker return 256;
232*a67afe4dSAndroid Build Coastguard Worker }
233*a67afe4dSAndroid Build Coastguard Worker }
234*a67afe4dSAndroid Build Coastguard Worker
235*a67afe4dSAndroid Build Coastguard Worker static void
set_color(png_colorp color,png_bytep trans,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha,png_const_bytep gamma_table)236*a67afe4dSAndroid Build Coastguard Worker set_color(png_colorp color, png_bytep trans, unsigned int red,
237*a67afe4dSAndroid Build Coastguard Worker unsigned int green, unsigned int blue, unsigned int alpha,
238*a67afe4dSAndroid Build Coastguard Worker png_const_bytep gamma_table)
239*a67afe4dSAndroid Build Coastguard Worker {
240*a67afe4dSAndroid Build Coastguard Worker color->red = gamma_table[red];
241*a67afe4dSAndroid Build Coastguard Worker color->green = gamma_table[green];
242*a67afe4dSAndroid Build Coastguard Worker color->blue = gamma_table[blue];
243*a67afe4dSAndroid Build Coastguard Worker *trans = (png_byte)alpha;
244*a67afe4dSAndroid Build Coastguard Worker }
245*a67afe4dSAndroid Build Coastguard Worker
246*a67afe4dSAndroid Build Coastguard Worker static int
generate_palette(png_colorp palette,png_bytep trans,int bit_depth,png_const_bytep gamma_table,unsigned int * colors)247*a67afe4dSAndroid Build Coastguard Worker generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
248*a67afe4dSAndroid Build Coastguard Worker png_const_bytep gamma_table, unsigned int *colors)
249*a67afe4dSAndroid Build Coastguard Worker {
250*a67afe4dSAndroid Build Coastguard Worker /*
251*a67afe4dSAndroid Build Coastguard Worker * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white
252*a67afe4dSAndroid Build Coastguard Worker * 2-bit: entry 0: transparent-green
253*a67afe4dSAndroid Build Coastguard Worker * entry 1: 40%-red
254*a67afe4dSAndroid Build Coastguard Worker * entry 2: 80%-blue
255*a67afe4dSAndroid Build Coastguard Worker * entry 3: opaque-white
256*a67afe4dSAndroid Build Coastguard Worker * 4-bit: the 16 combinations of the 2-bit case
257*a67afe4dSAndroid Build Coastguard Worker * 8-bit: the 256 combinations of the 4-bit case
258*a67afe4dSAndroid Build Coastguard Worker */
259*a67afe4dSAndroid Build Coastguard Worker switch (colors[0])
260*a67afe4dSAndroid Build Coastguard Worker {
261*a67afe4dSAndroid Build Coastguard Worker default:
262*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: --colors=...: invalid count %u\n",
263*a67afe4dSAndroid Build Coastguard Worker colors[0]);
264*a67afe4dSAndroid Build Coastguard Worker exit(1);
265*a67afe4dSAndroid Build Coastguard Worker
266*a67afe4dSAndroid Build Coastguard Worker case 1:
267*a67afe4dSAndroid Build Coastguard Worker set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255,
268*a67afe4dSAndroid Build Coastguard Worker gamma_table);
269*a67afe4dSAndroid Build Coastguard Worker return 1;
270*a67afe4dSAndroid Build Coastguard Worker
271*a67afe4dSAndroid Build Coastguard Worker case 2:
272*a67afe4dSAndroid Build Coastguard Worker set_color(palette+0, trans+0, colors[1], colors[1], colors[1],
273*a67afe4dSAndroid Build Coastguard Worker colors[2], gamma_table);
274*a67afe4dSAndroid Build Coastguard Worker return 1;
275*a67afe4dSAndroid Build Coastguard Worker
276*a67afe4dSAndroid Build Coastguard Worker case 3:
277*a67afe4dSAndroid Build Coastguard Worker set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255,
278*a67afe4dSAndroid Build Coastguard Worker gamma_table);
279*a67afe4dSAndroid Build Coastguard Worker return 1;
280*a67afe4dSAndroid Build Coastguard Worker
281*a67afe4dSAndroid Build Coastguard Worker case 4:
282*a67afe4dSAndroid Build Coastguard Worker set_color(palette+0, trans+0, colors[1], colors[2], colors[3],
283*a67afe4dSAndroid Build Coastguard Worker colors[4], gamma_table);
284*a67afe4dSAndroid Build Coastguard Worker return 1;
285*a67afe4dSAndroid Build Coastguard Worker
286*a67afe4dSAndroid Build Coastguard Worker case 0:
287*a67afe4dSAndroid Build Coastguard Worker if (bit_depth == 1)
288*a67afe4dSAndroid Build Coastguard Worker {
289*a67afe4dSAndroid Build Coastguard Worker set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table);
290*a67afe4dSAndroid Build Coastguard Worker set_color(palette+1, trans+1, 255, 255, 255, 255, gamma_table);
291*a67afe4dSAndroid Build Coastguard Worker return 2;
292*a67afe4dSAndroid Build Coastguard Worker }
293*a67afe4dSAndroid Build Coastguard Worker
294*a67afe4dSAndroid Build Coastguard Worker else
295*a67afe4dSAndroid Build Coastguard Worker {
296*a67afe4dSAndroid Build Coastguard Worker unsigned int size = 1U << (bit_depth/2); /* 2, 4 or 16 */
297*a67afe4dSAndroid Build Coastguard Worker unsigned int x, y;
298*a67afe4dSAndroid Build Coastguard Worker volatile unsigned int ip = 0;
299*a67afe4dSAndroid Build Coastguard Worker
300*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<size; ++x)
301*a67afe4dSAndroid Build Coastguard Worker {
302*a67afe4dSAndroid Build Coastguard Worker for (y=0; y<size; ++y)
303*a67afe4dSAndroid Build Coastguard Worker {
304*a67afe4dSAndroid Build Coastguard Worker ip = x + (size * y);
305*a67afe4dSAndroid Build Coastguard Worker
306*a67afe4dSAndroid Build Coastguard Worker /* size is at most 16, so the scaled value below fits in 16 bits
307*a67afe4dSAndroid Build Coastguard Worker */
308*a67afe4dSAndroid Build Coastguard Worker # define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2))
309*a67afe4dSAndroid Build Coastguard Worker # define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\
310*a67afe4dSAndroid Build Coastguard Worker (interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\
311*a67afe4dSAndroid Build Coastguard Worker (size*size))
312*a67afe4dSAndroid Build Coastguard Worker
313*a67afe4dSAndroid Build Coastguard Worker set_color(palette+ip, trans+ip,
314*a67afe4dSAndroid Build Coastguard Worker /* color: green, red,blue,white */
315*a67afe4dSAndroid Build Coastguard Worker xyinterp(x, y, 0, 255, 0, 255),
316*a67afe4dSAndroid Build Coastguard Worker xyinterp(x, y, 255, 0, 0, 255),
317*a67afe4dSAndroid Build Coastguard Worker xyinterp(x, y, 0, 0, 255, 255),
318*a67afe4dSAndroid Build Coastguard Worker /* alpha: 0, 102, 204, 255) */
319*a67afe4dSAndroid Build Coastguard Worker xyinterp(x, y, 0, 102, 204, 255),
320*a67afe4dSAndroid Build Coastguard Worker gamma_table);
321*a67afe4dSAndroid Build Coastguard Worker }
322*a67afe4dSAndroid Build Coastguard Worker }
323*a67afe4dSAndroid Build Coastguard Worker
324*a67afe4dSAndroid Build Coastguard Worker return ip+1;
325*a67afe4dSAndroid Build Coastguard Worker }
326*a67afe4dSAndroid Build Coastguard Worker }
327*a67afe4dSAndroid Build Coastguard Worker }
328*a67afe4dSAndroid Build Coastguard Worker
329*a67afe4dSAndroid Build Coastguard Worker static void
set_value(png_bytep row,size_t rowbytes,png_uint_32 x,unsigned int bit_depth,png_uint_32 value,png_const_bytep gamma_table,double conv)330*a67afe4dSAndroid Build Coastguard Worker set_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth,
331*a67afe4dSAndroid Build Coastguard Worker png_uint_32 value, png_const_bytep gamma_table, double conv)
332*a67afe4dSAndroid Build Coastguard Worker {
333*a67afe4dSAndroid Build Coastguard Worker unsigned int mask = (1U << bit_depth)-1;
334*a67afe4dSAndroid Build Coastguard Worker
335*a67afe4dSAndroid Build Coastguard Worker x *= bit_depth; /* Maximum x is 4*1024, maximum bit_depth is 16 */
336*a67afe4dSAndroid Build Coastguard Worker
337*a67afe4dSAndroid Build Coastguard Worker if (value <= mask)
338*a67afe4dSAndroid Build Coastguard Worker {
339*a67afe4dSAndroid Build Coastguard Worker png_uint_32 offset = x >> 3;
340*a67afe4dSAndroid Build Coastguard Worker
341*a67afe4dSAndroid Build Coastguard Worker if (offset < rowbytes && (bit_depth < 16 || offset+1 < rowbytes))
342*a67afe4dSAndroid Build Coastguard Worker {
343*a67afe4dSAndroid Build Coastguard Worker row += offset;
344*a67afe4dSAndroid Build Coastguard Worker
345*a67afe4dSAndroid Build Coastguard Worker switch (bit_depth)
346*a67afe4dSAndroid Build Coastguard Worker {
347*a67afe4dSAndroid Build Coastguard Worker case 1:
348*a67afe4dSAndroid Build Coastguard Worker case 2:
349*a67afe4dSAndroid Build Coastguard Worker case 4:
350*a67afe4dSAndroid Build Coastguard Worker /* Don't gamma correct - values get smashed */
351*a67afe4dSAndroid Build Coastguard Worker {
352*a67afe4dSAndroid Build Coastguard Worker unsigned int shift = (8 - bit_depth) - (x & 0x7U);
353*a67afe4dSAndroid Build Coastguard Worker
354*a67afe4dSAndroid Build Coastguard Worker mask <<= shift;
355*a67afe4dSAndroid Build Coastguard Worker value = (value << shift) & mask;
356*a67afe4dSAndroid Build Coastguard Worker *row = (png_byte)((*row & ~mask) | value);
357*a67afe4dSAndroid Build Coastguard Worker }
358*a67afe4dSAndroid Build Coastguard Worker return;
359*a67afe4dSAndroid Build Coastguard Worker
360*a67afe4dSAndroid Build Coastguard Worker default:
361*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: bad bit depth (internal error)\n");
362*a67afe4dSAndroid Build Coastguard Worker exit(1);
363*a67afe4dSAndroid Build Coastguard Worker
364*a67afe4dSAndroid Build Coastguard Worker case 16:
365*a67afe4dSAndroid Build Coastguard Worker value = flooru(65535*pow(value/65535.,conv)+.5);
366*a67afe4dSAndroid Build Coastguard Worker *row++ = (png_byte)(value >> 8);
367*a67afe4dSAndroid Build Coastguard Worker *row = (png_byte)value;
368*a67afe4dSAndroid Build Coastguard Worker return;
369*a67afe4dSAndroid Build Coastguard Worker
370*a67afe4dSAndroid Build Coastguard Worker case 8:
371*a67afe4dSAndroid Build Coastguard Worker *row = gamma_table[value];
372*a67afe4dSAndroid Build Coastguard Worker return;
373*a67afe4dSAndroid Build Coastguard Worker }
374*a67afe4dSAndroid Build Coastguard Worker }
375*a67afe4dSAndroid Build Coastguard Worker
376*a67afe4dSAndroid Build Coastguard Worker else
377*a67afe4dSAndroid Build Coastguard Worker {
378*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: row buffer overflow (internal error)\n");
379*a67afe4dSAndroid Build Coastguard Worker exit(1);
380*a67afe4dSAndroid Build Coastguard Worker }
381*a67afe4dSAndroid Build Coastguard Worker }
382*a67afe4dSAndroid Build Coastguard Worker
383*a67afe4dSAndroid Build Coastguard Worker else
384*a67afe4dSAndroid Build Coastguard Worker {
385*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: component overflow (internal error)\n");
386*a67afe4dSAndroid Build Coastguard Worker exit(1);
387*a67afe4dSAndroid Build Coastguard Worker }
388*a67afe4dSAndroid Build Coastguard Worker }
389*a67afe4dSAndroid Build Coastguard Worker
390*a67afe4dSAndroid Build Coastguard Worker static int /* filter mask for row */
generate_row(png_bytep row,size_t rowbytes,unsigned int y,int color_type,int bit_depth,png_const_bytep gamma_table,double conv,unsigned int * colors,int small)391*a67afe4dSAndroid Build Coastguard Worker generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
392*a67afe4dSAndroid Build Coastguard Worker int bit_depth, png_const_bytep gamma_table, double conv,
393*a67afe4dSAndroid Build Coastguard Worker unsigned int *colors, int small)
394*a67afe4dSAndroid Build Coastguard Worker {
395*a67afe4dSAndroid Build Coastguard Worker int filters = 0; /* file *MASK*, 0 means the default, not NONE */
396*a67afe4dSAndroid Build Coastguard Worker png_uint_32 size_max =
397*a67afe4dSAndroid Build Coastguard Worker image_size_of_type(color_type, bit_depth, colors, small)-1;
398*a67afe4dSAndroid Build Coastguard Worker png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */
399*a67afe4dSAndroid Build Coastguard Worker
400*a67afe4dSAndroid Build Coastguard Worker if (colors[0] == 0 && small)
401*a67afe4dSAndroid Build Coastguard Worker {
402*a67afe4dSAndroid Build Coastguard Worker unsigned int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
403*a67afe4dSAndroid Build Coastguard Worker
404*a67afe4dSAndroid Build Coastguard Worker /* For pixel depths less than 16 generate a single row containing all the
405*a67afe4dSAndroid Build Coastguard Worker * possible pixel values. For 16 generate all 65536 byte pair
406*a67afe4dSAndroid Build Coastguard Worker * combinations in a 256x256 pixel array.
407*a67afe4dSAndroid Build Coastguard Worker */
408*a67afe4dSAndroid Build Coastguard Worker switch (pixel_depth)
409*a67afe4dSAndroid Build Coastguard Worker {
410*a67afe4dSAndroid Build Coastguard Worker case 1:
411*a67afe4dSAndroid Build Coastguard Worker assert(y == 0 && rowbytes == 1 && size_max == 1);
412*a67afe4dSAndroid Build Coastguard Worker row[0] = 0x6CU; /* binary: 01101100, only top 2 bits used */
413*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_NONE;
414*a67afe4dSAndroid Build Coastguard Worker break;
415*a67afe4dSAndroid Build Coastguard Worker
416*a67afe4dSAndroid Build Coastguard Worker case 2:
417*a67afe4dSAndroid Build Coastguard Worker assert(y == 0 && rowbytes == 1 && size_max == 3);
418*a67afe4dSAndroid Build Coastguard Worker row[0] = 0x1BU; /* binary 00011011, all bits used */
419*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_NONE;
420*a67afe4dSAndroid Build Coastguard Worker break;
421*a67afe4dSAndroid Build Coastguard Worker
422*a67afe4dSAndroid Build Coastguard Worker case 4:
423*a67afe4dSAndroid Build Coastguard Worker assert(y == 0 && rowbytes == 8 && size_max == 15);
424*a67afe4dSAndroid Build Coastguard Worker row[0] = 0x01U;
425*a67afe4dSAndroid Build Coastguard Worker row[1] = 0x23U; /* SUB gives 0x22U for all following bytes */
426*a67afe4dSAndroid Build Coastguard Worker row[2] = 0x45U;
427*a67afe4dSAndroid Build Coastguard Worker row[3] = 0x67U;
428*a67afe4dSAndroid Build Coastguard Worker row[4] = 0x89U;
429*a67afe4dSAndroid Build Coastguard Worker row[5] = 0xABU;
430*a67afe4dSAndroid Build Coastguard Worker row[6] = 0xCDU;
431*a67afe4dSAndroid Build Coastguard Worker row[7] = 0xEFU;
432*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_SUB;
433*a67afe4dSAndroid Build Coastguard Worker break;
434*a67afe4dSAndroid Build Coastguard Worker
435*a67afe4dSAndroid Build Coastguard Worker case 8:
436*a67afe4dSAndroid Build Coastguard Worker /* The row will have all the pixel values in order starting with
437*a67afe4dSAndroid Build Coastguard Worker * '1', the SUB filter will change every byte into '1' (including
438*a67afe4dSAndroid Build Coastguard Worker * the last, which generates pixel value '0'). Since the SUB filter
439*a67afe4dSAndroid Build Coastguard Worker * has value 1 this should result in maximum compression.
440*a67afe4dSAndroid Build Coastguard Worker */
441*a67afe4dSAndroid Build Coastguard Worker assert(y == 0 && rowbytes == 256 && size_max == 255);
442*a67afe4dSAndroid Build Coastguard Worker for (;;)
443*a67afe4dSAndroid Build Coastguard Worker {
444*a67afe4dSAndroid Build Coastguard Worker row[size_max] = 0xFFU & (size_max+1);
445*a67afe4dSAndroid Build Coastguard Worker if (size_max == 0)
446*a67afe4dSAndroid Build Coastguard Worker break;
447*a67afe4dSAndroid Build Coastguard Worker --size_max;
448*a67afe4dSAndroid Build Coastguard Worker }
449*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_SUB;
450*a67afe4dSAndroid Build Coastguard Worker break;
451*a67afe4dSAndroid Build Coastguard Worker
452*a67afe4dSAndroid Build Coastguard Worker case 16:
453*a67afe4dSAndroid Build Coastguard Worker /* Rows are generated such that each row has a constant difference
454*a67afe4dSAndroid Build Coastguard Worker * between the first and second byte of each pixel and so that the
455*a67afe4dSAndroid Build Coastguard Worker * difference increases by 1 at each row. The rows start with the
456*a67afe4dSAndroid Build Coastguard Worker * first byte value of 0 and the value increases to 255 across the
457*a67afe4dSAndroid Build Coastguard Worker * row.
458*a67afe4dSAndroid Build Coastguard Worker *
459*a67afe4dSAndroid Build Coastguard Worker * The difference starts at 1, so the first row is:
460*a67afe4dSAndroid Build Coastguard Worker *
461*a67afe4dSAndroid Build Coastguard Worker * 0 1 1 2 2 3 3 4 ... 254 255 255 0
462*a67afe4dSAndroid Build Coastguard Worker *
463*a67afe4dSAndroid Build Coastguard Worker * This means that running the SUB filter on the first row produces:
464*a67afe4dSAndroid Build Coastguard Worker *
465*a67afe4dSAndroid Build Coastguard Worker * [SUB==1] 0 1 0 1 0 1...
466*a67afe4dSAndroid Build Coastguard Worker *
467*a67afe4dSAndroid Build Coastguard Worker * Then the difference is 2 on the next row, giving:
468*a67afe4dSAndroid Build Coastguard Worker *
469*a67afe4dSAndroid Build Coastguard Worker * 0 2 1 3 2 4 3 5 ... 254 0 255 1
470*a67afe4dSAndroid Build Coastguard Worker *
471*a67afe4dSAndroid Build Coastguard Worker * When the UP filter is run on this libpng produces:
472*a67afe4dSAndroid Build Coastguard Worker *
473*a67afe4dSAndroid Build Coastguard Worker * [UP ==2] 0 1 0 1 0 1...
474*a67afe4dSAndroid Build Coastguard Worker *
475*a67afe4dSAndroid Build Coastguard Worker * And so on for all the remain rows to the final two * rows:
476*a67afe4dSAndroid Build Coastguard Worker *
477*a67afe4dSAndroid Build Coastguard Worker * row 254: 0 255 1 0 2 1 3 2 4 3 ... 254 253 255 254
478*a67afe4dSAndroid Build Coastguard Worker * row 255: 0 0 1 1 2 2 3 3 4 4 ... 254 254 255 255
479*a67afe4dSAndroid Build Coastguard Worker */
480*a67afe4dSAndroid Build Coastguard Worker assert(rowbytes == 512 && size_max == 255);
481*a67afe4dSAndroid Build Coastguard Worker for (;;)
482*a67afe4dSAndroid Build Coastguard Worker {
483*a67afe4dSAndroid Build Coastguard Worker row[2*size_max ] = 0xFFU & size_max;
484*a67afe4dSAndroid Build Coastguard Worker row[2*size_max+1] = 0xFFU & (size_max+y+1);
485*a67afe4dSAndroid Build Coastguard Worker if (size_max == 0)
486*a67afe4dSAndroid Build Coastguard Worker break;
487*a67afe4dSAndroid Build Coastguard Worker --size_max;
488*a67afe4dSAndroid Build Coastguard Worker }
489*a67afe4dSAndroid Build Coastguard Worker /* The first row must include PNG_FILTER_UP so that libpng knows we
490*a67afe4dSAndroid Build Coastguard Worker * need to keep it for the following row:
491*a67afe4dSAndroid Build Coastguard Worker */
492*a67afe4dSAndroid Build Coastguard Worker filters = (y == 0 ? PNG_FILTER_SUB+PNG_FILTER_UP : PNG_FILTER_UP);
493*a67afe4dSAndroid Build Coastguard Worker break;
494*a67afe4dSAndroid Build Coastguard Worker
495*a67afe4dSAndroid Build Coastguard Worker case 24:
496*a67afe4dSAndroid Build Coastguard Worker case 32:
497*a67afe4dSAndroid Build Coastguard Worker case 48:
498*a67afe4dSAndroid Build Coastguard Worker case 64:
499*a67afe4dSAndroid Build Coastguard Worker /* The rows are filled by an algorithm similar to the above, in the
500*a67afe4dSAndroid Build Coastguard Worker * first row pixel bytes are all equal, increasing from 0 by 1 for
501*a67afe4dSAndroid Build Coastguard Worker * each pixel. In the second row the bytes within a pixel are
502*a67afe4dSAndroid Build Coastguard Worker * incremented 1,3,5,7,... from the previous row byte. Using an odd
503*a67afe4dSAndroid Build Coastguard Worker * number ensures all the possible byte values are used.
504*a67afe4dSAndroid Build Coastguard Worker */
505*a67afe4dSAndroid Build Coastguard Worker assert(size_max == 255 && rowbytes == 256*(pixel_depth>>3));
506*a67afe4dSAndroid Build Coastguard Worker pixel_depth >>= 3; /* now in bytes */
507*a67afe4dSAndroid Build Coastguard Worker while (rowbytes > 0)
508*a67afe4dSAndroid Build Coastguard Worker {
509*a67afe4dSAndroid Build Coastguard Worker const size_t pixel_index = --rowbytes/pixel_depth;
510*a67afe4dSAndroid Build Coastguard Worker
511*a67afe4dSAndroid Build Coastguard Worker if (y == 0)
512*a67afe4dSAndroid Build Coastguard Worker row[rowbytes] = 0xFFU & pixel_index;
513*a67afe4dSAndroid Build Coastguard Worker
514*a67afe4dSAndroid Build Coastguard Worker else
515*a67afe4dSAndroid Build Coastguard Worker {
516*a67afe4dSAndroid Build Coastguard Worker const size_t byte_offset =
517*a67afe4dSAndroid Build Coastguard Worker rowbytes - pixel_index * pixel_depth;
518*a67afe4dSAndroid Build Coastguard Worker
519*a67afe4dSAndroid Build Coastguard Worker row[rowbytes] =
520*a67afe4dSAndroid Build Coastguard Worker 0xFFU & (pixel_index + (byte_offset * 2*y) + 1);
521*a67afe4dSAndroid Build Coastguard Worker }
522*a67afe4dSAndroid Build Coastguard Worker }
523*a67afe4dSAndroid Build Coastguard Worker filters = (y == 0 ? PNG_FILTER_SUB+PNG_FILTER_UP : PNG_FILTER_UP);
524*a67afe4dSAndroid Build Coastguard Worker break;
525*a67afe4dSAndroid Build Coastguard Worker
526*a67afe4dSAndroid Build Coastguard Worker default:
527*a67afe4dSAndroid Build Coastguard Worker assert(0/*NOT REACHED*/);
528*a67afe4dSAndroid Build Coastguard Worker }
529*a67afe4dSAndroid Build Coastguard Worker }
530*a67afe4dSAndroid Build Coastguard Worker
531*a67afe4dSAndroid Build Coastguard Worker else switch (channels_of_type(color_type))
532*a67afe4dSAndroid Build Coastguard Worker {
533*a67afe4dSAndroid Build Coastguard Worker /* 1 channel: a square image with a diamond, the least luminous colors are on
534*a67afe4dSAndroid Build Coastguard Worker * the edge of the image, the most luminous in the center.
535*a67afe4dSAndroid Build Coastguard Worker */
536*a67afe4dSAndroid Build Coastguard Worker case 1:
537*a67afe4dSAndroid Build Coastguard Worker {
538*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
539*a67afe4dSAndroid Build Coastguard Worker png_uint_32 base = 2*size_max - abs(2*y-size_max);
540*a67afe4dSAndroid Build Coastguard Worker
541*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<=size_max; ++x)
542*a67afe4dSAndroid Build Coastguard Worker {
543*a67afe4dSAndroid Build Coastguard Worker png_uint_32 luma = base - abs(2*x-size_max);
544*a67afe4dSAndroid Build Coastguard Worker
545*a67afe4dSAndroid Build Coastguard Worker /* 'luma' is now in the range 0..2*size_max, we need
546*a67afe4dSAndroid Build Coastguard Worker * 0..depth_max
547*a67afe4dSAndroid Build Coastguard Worker */
548*a67afe4dSAndroid Build Coastguard Worker luma = (luma*depth_max + size_max) / (2*size_max);
549*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, x, bit_depth, luma, gamma_table, conv);
550*a67afe4dSAndroid Build Coastguard Worker }
551*a67afe4dSAndroid Build Coastguard Worker }
552*a67afe4dSAndroid Build Coastguard Worker break;
553*a67afe4dSAndroid Build Coastguard Worker
554*a67afe4dSAndroid Build Coastguard Worker /* 2 channels: the color channel increases in luminosity from top to bottom,
555*a67afe4dSAndroid Build Coastguard Worker * the alpha channel increases in opacity from left to right.
556*a67afe4dSAndroid Build Coastguard Worker */
557*a67afe4dSAndroid Build Coastguard Worker case 2:
558*a67afe4dSAndroid Build Coastguard Worker {
559*a67afe4dSAndroid Build Coastguard Worker png_uint_32 alpha = (depth_max * y * 2 + size_max) / (2 * size_max);
560*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
561*a67afe4dSAndroid Build Coastguard Worker
562*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<=size_max; ++x)
563*a67afe4dSAndroid Build Coastguard Worker {
564*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 2*x, bit_depth,
565*a67afe4dSAndroid Build Coastguard Worker (depth_max * x * 2 + size_max) / (2 * size_max), gamma_table,
566*a67afe4dSAndroid Build Coastguard Worker conv);
567*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table,
568*a67afe4dSAndroid Build Coastguard Worker conv);
569*a67afe4dSAndroid Build Coastguard Worker }
570*a67afe4dSAndroid Build Coastguard Worker }
571*a67afe4dSAndroid Build Coastguard Worker break;
572*a67afe4dSAndroid Build Coastguard Worker
573*a67afe4dSAndroid Build Coastguard Worker /* 3 channels: linear combinations of, from the top-left corner clockwise,
574*a67afe4dSAndroid Build Coastguard Worker * black, green, white, red.
575*a67afe4dSAndroid Build Coastguard Worker */
576*a67afe4dSAndroid Build Coastguard Worker case 3:
577*a67afe4dSAndroid Build Coastguard Worker {
578*a67afe4dSAndroid Build Coastguard Worker /* x0: the black->red scale (the value of the red component) at the
579*a67afe4dSAndroid Build Coastguard Worker * start of the row (blue and green are 0).
580*a67afe4dSAndroid Build Coastguard Worker * x1: the green->white scale (the value of the red and blue
581*a67afe4dSAndroid Build Coastguard Worker * components at the end of the row; green is depth_max).
582*a67afe4dSAndroid Build Coastguard Worker */
583*a67afe4dSAndroid Build Coastguard Worker png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max);
584*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
585*a67afe4dSAndroid Build Coastguard Worker
586*a67afe4dSAndroid Build Coastguard Worker /* Interpolate x/depth_max from start to end:
587*a67afe4dSAndroid Build Coastguard Worker *
588*a67afe4dSAndroid Build Coastguard Worker * start end difference
589*a67afe4dSAndroid Build Coastguard Worker * red: Y Y 0
590*a67afe4dSAndroid Build Coastguard Worker * green: 0 depth_max depth_max
591*a67afe4dSAndroid Build Coastguard Worker * blue: 0 Y Y
592*a67afe4dSAndroid Build Coastguard Worker */
593*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<=size_max; ++x)
594*a67afe4dSAndroid Build Coastguard Worker {
595*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 3*x+0, bit_depth, /* red */ Y,
596*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv);
597*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 3*x+1, bit_depth, /* green */
598*a67afe4dSAndroid Build Coastguard Worker (depth_max * x * 2 + size_max) / (2 * size_max),
599*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv);
600*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 3*x+2, bit_depth, /* blue */
601*a67afe4dSAndroid Build Coastguard Worker (Y * x * 2 + size_max) / (2 * size_max),
602*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv);
603*a67afe4dSAndroid Build Coastguard Worker }
604*a67afe4dSAndroid Build Coastguard Worker }
605*a67afe4dSAndroid Build Coastguard Worker break;
606*a67afe4dSAndroid Build Coastguard Worker
607*a67afe4dSAndroid Build Coastguard Worker /* 4 channels: linear combinations of, from the top-left corner clockwise,
608*a67afe4dSAndroid Build Coastguard Worker * transparent, red, green, blue.
609*a67afe4dSAndroid Build Coastguard Worker */
610*a67afe4dSAndroid Build Coastguard Worker case 4:
611*a67afe4dSAndroid Build Coastguard Worker {
612*a67afe4dSAndroid Build Coastguard Worker /* x0: the transparent->blue scale (the value of the blue and alpha
613*a67afe4dSAndroid Build Coastguard Worker * components) at the start of the row (red and green are 0).
614*a67afe4dSAndroid Build Coastguard Worker * x1: the red->green scale (the value of the red and green
615*a67afe4dSAndroid Build Coastguard Worker * components at the end of the row; blue is 0 and alpha is
616*a67afe4dSAndroid Build Coastguard Worker * depth_max).
617*a67afe4dSAndroid Build Coastguard Worker */
618*a67afe4dSAndroid Build Coastguard Worker png_uint_32 Y = (depth_max * y * 2 + size_max) / (2 * size_max);
619*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
620*a67afe4dSAndroid Build Coastguard Worker
621*a67afe4dSAndroid Build Coastguard Worker /* Interpolate x/depth_max from start to end:
622*a67afe4dSAndroid Build Coastguard Worker *
623*a67afe4dSAndroid Build Coastguard Worker * start end difference
624*a67afe4dSAndroid Build Coastguard Worker * red: 0 depth_max-Y depth_max-Y
625*a67afe4dSAndroid Build Coastguard Worker * green: 0 Y Y
626*a67afe4dSAndroid Build Coastguard Worker * blue: Y 0 -Y
627*a67afe4dSAndroid Build Coastguard Worker * alpha: Y depth_max depth_max-Y
628*a67afe4dSAndroid Build Coastguard Worker */
629*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<=size_max; ++x)
630*a67afe4dSAndroid Build Coastguard Worker {
631*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+0, bit_depth, /* red */
632*a67afe4dSAndroid Build Coastguard Worker ((depth_max-Y) * x * 2 + size_max) / (2 * size_max),
633*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv);
634*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+1, bit_depth, /* green */
635*a67afe4dSAndroid Build Coastguard Worker (Y * x * 2 + size_max) / (2 * size_max),
636*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv);
637*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+2, bit_depth, /* blue */
638*a67afe4dSAndroid Build Coastguard Worker Y - (Y * x * 2 + size_max) / (2 * size_max),
639*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv);
640*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+3, bit_depth, /* alpha */
641*a67afe4dSAndroid Build Coastguard Worker Y + ((depth_max-Y) * x * 2 + size_max) / (2 * size_max),
642*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv);
643*a67afe4dSAndroid Build Coastguard Worker }
644*a67afe4dSAndroid Build Coastguard Worker }
645*a67afe4dSAndroid Build Coastguard Worker break;
646*a67afe4dSAndroid Build Coastguard Worker
647*a67afe4dSAndroid Build Coastguard Worker default:
648*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: internal bad channel count\n");
649*a67afe4dSAndroid Build Coastguard Worker exit(2);
650*a67afe4dSAndroid Build Coastguard Worker }
651*a67afe4dSAndroid Build Coastguard Worker
652*a67afe4dSAndroid Build Coastguard Worker else if (color_type & PNG_COLOR_MASK_PALETTE)
653*a67afe4dSAndroid Build Coastguard Worker {
654*a67afe4dSAndroid Build Coastguard Worker /* Palette with fixed color: the image rows are all 0 and the image width
655*a67afe4dSAndroid Build Coastguard Worker * is 16.
656*a67afe4dSAndroid Build Coastguard Worker */
657*a67afe4dSAndroid Build Coastguard Worker memset(row, 0, rowbytes);
658*a67afe4dSAndroid Build Coastguard Worker }
659*a67afe4dSAndroid Build Coastguard Worker
660*a67afe4dSAndroid Build Coastguard Worker else if (colors[0] == channels_of_type(color_type))
661*a67afe4dSAndroid Build Coastguard Worker switch (channels_of_type(color_type))
662*a67afe4dSAndroid Build Coastguard Worker {
663*a67afe4dSAndroid Build Coastguard Worker case 1:
664*a67afe4dSAndroid Build Coastguard Worker {
665*a67afe4dSAndroid Build Coastguard Worker png_uint_32 luma = colors[1];
666*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
667*a67afe4dSAndroid Build Coastguard Worker
668*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<=size_max; ++x)
669*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, x, bit_depth, luma, gamma_table,
670*a67afe4dSAndroid Build Coastguard Worker conv);
671*a67afe4dSAndroid Build Coastguard Worker }
672*a67afe4dSAndroid Build Coastguard Worker break;
673*a67afe4dSAndroid Build Coastguard Worker
674*a67afe4dSAndroid Build Coastguard Worker case 2:
675*a67afe4dSAndroid Build Coastguard Worker {
676*a67afe4dSAndroid Build Coastguard Worker png_uint_32 luma = colors[1];
677*a67afe4dSAndroid Build Coastguard Worker png_uint_32 alpha = colors[2];
678*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
679*a67afe4dSAndroid Build Coastguard Worker
680*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<size_max; ++x)
681*a67afe4dSAndroid Build Coastguard Worker {
682*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 2*x, bit_depth, luma, gamma_table,
683*a67afe4dSAndroid Build Coastguard Worker conv);
684*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table,
685*a67afe4dSAndroid Build Coastguard Worker conv);
686*a67afe4dSAndroid Build Coastguard Worker }
687*a67afe4dSAndroid Build Coastguard Worker }
688*a67afe4dSAndroid Build Coastguard Worker break;
689*a67afe4dSAndroid Build Coastguard Worker
690*a67afe4dSAndroid Build Coastguard Worker case 3:
691*a67afe4dSAndroid Build Coastguard Worker {
692*a67afe4dSAndroid Build Coastguard Worker png_uint_32 red = colors[1];
693*a67afe4dSAndroid Build Coastguard Worker png_uint_32 green = colors[2];
694*a67afe4dSAndroid Build Coastguard Worker png_uint_32 blue = colors[3];
695*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
696*a67afe4dSAndroid Build Coastguard Worker
697*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<=size_max; ++x)
698*a67afe4dSAndroid Build Coastguard Worker {
699*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 3*x+0, bit_depth, red, gamma_table,
700*a67afe4dSAndroid Build Coastguard Worker conv);
701*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 3*x+1, bit_depth, green, gamma_table,
702*a67afe4dSAndroid Build Coastguard Worker conv);
703*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 3*x+2, bit_depth, blue, gamma_table,
704*a67afe4dSAndroid Build Coastguard Worker conv);
705*a67afe4dSAndroid Build Coastguard Worker }
706*a67afe4dSAndroid Build Coastguard Worker }
707*a67afe4dSAndroid Build Coastguard Worker break;
708*a67afe4dSAndroid Build Coastguard Worker
709*a67afe4dSAndroid Build Coastguard Worker case 4:
710*a67afe4dSAndroid Build Coastguard Worker {
711*a67afe4dSAndroid Build Coastguard Worker png_uint_32 red = colors[1];
712*a67afe4dSAndroid Build Coastguard Worker png_uint_32 green = colors[2];
713*a67afe4dSAndroid Build Coastguard Worker png_uint_32 blue = colors[3];
714*a67afe4dSAndroid Build Coastguard Worker png_uint_32 alpha = colors[4];
715*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x;
716*a67afe4dSAndroid Build Coastguard Worker
717*a67afe4dSAndroid Build Coastguard Worker for (x=0; x<=size_max; ++x)
718*a67afe4dSAndroid Build Coastguard Worker {
719*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+0, bit_depth, red, gamma_table,
720*a67afe4dSAndroid Build Coastguard Worker conv);
721*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+1, bit_depth, green, gamma_table,
722*a67afe4dSAndroid Build Coastguard Worker conv);
723*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+2, bit_depth, blue, gamma_table,
724*a67afe4dSAndroid Build Coastguard Worker conv);
725*a67afe4dSAndroid Build Coastguard Worker set_value(row, rowbytes, 4*x+3, bit_depth, alpha, gamma_table,
726*a67afe4dSAndroid Build Coastguard Worker conv);
727*a67afe4dSAndroid Build Coastguard Worker }
728*a67afe4dSAndroid Build Coastguard Worker }
729*a67afe4dSAndroid Build Coastguard Worker break;
730*a67afe4dSAndroid Build Coastguard Worker
731*a67afe4dSAndroid Build Coastguard Worker default:
732*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: internal bad channel count\n");
733*a67afe4dSAndroid Build Coastguard Worker exit(2);
734*a67afe4dSAndroid Build Coastguard Worker }
735*a67afe4dSAndroid Build Coastguard Worker
736*a67afe4dSAndroid Build Coastguard Worker else
737*a67afe4dSAndroid Build Coastguard Worker {
738*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr,
739*a67afe4dSAndroid Build Coastguard Worker "makepng: --color: count(%u) does not match channels(%u)\n",
740*a67afe4dSAndroid Build Coastguard Worker colors[0], channels_of_type(color_type));
741*a67afe4dSAndroid Build Coastguard Worker exit(1);
742*a67afe4dSAndroid Build Coastguard Worker }
743*a67afe4dSAndroid Build Coastguard Worker
744*a67afe4dSAndroid Build Coastguard Worker return filters;
745*a67afe4dSAndroid Build Coastguard Worker }
746*a67afe4dSAndroid Build Coastguard Worker
747*a67afe4dSAndroid Build Coastguard Worker
748*a67afe4dSAndroid Build Coastguard Worker static void PNGCBAPI
makepng_warning(png_structp png_ptr,png_const_charp message)749*a67afe4dSAndroid Build Coastguard Worker makepng_warning(png_structp png_ptr, png_const_charp message)
750*a67afe4dSAndroid Build Coastguard Worker {
751*a67afe4dSAndroid Build Coastguard Worker const char **ep = png_get_error_ptr(png_ptr);
752*a67afe4dSAndroid Build Coastguard Worker const char *name;
753*a67afe4dSAndroid Build Coastguard Worker
754*a67afe4dSAndroid Build Coastguard Worker if (ep != NULL && *ep != NULL)
755*a67afe4dSAndroid Build Coastguard Worker name = *ep;
756*a67afe4dSAndroid Build Coastguard Worker
757*a67afe4dSAndroid Build Coastguard Worker else
758*a67afe4dSAndroid Build Coastguard Worker name = "makepng";
759*a67afe4dSAndroid Build Coastguard Worker
760*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: warning: %s\n", name, message);
761*a67afe4dSAndroid Build Coastguard Worker }
762*a67afe4dSAndroid Build Coastguard Worker
763*a67afe4dSAndroid Build Coastguard Worker static void PNGCBAPI
makepng_error(png_structp png_ptr,png_const_charp message)764*a67afe4dSAndroid Build Coastguard Worker makepng_error(png_structp png_ptr, png_const_charp message)
765*a67afe4dSAndroid Build Coastguard Worker {
766*a67afe4dSAndroid Build Coastguard Worker makepng_warning(png_ptr, message);
767*a67afe4dSAndroid Build Coastguard Worker png_longjmp(png_ptr, 1);
768*a67afe4dSAndroid Build Coastguard Worker }
769*a67afe4dSAndroid Build Coastguard Worker
770*a67afe4dSAndroid Build Coastguard Worker static int /* 0 on success, else an error code */
write_png(const char ** name,FILE * fp,int color_type,int bit_depth,volatile png_fixed_point gamma,chunk_insert * volatile insert,unsigned int filters,unsigned int * colors,int small,int tRNS)771*a67afe4dSAndroid Build Coastguard Worker write_png(const char **name, FILE *fp, int color_type, int bit_depth,
772*a67afe4dSAndroid Build Coastguard Worker volatile png_fixed_point gamma, chunk_insert * volatile insert,
773*a67afe4dSAndroid Build Coastguard Worker unsigned int filters, unsigned int *colors, int small, int tRNS)
774*a67afe4dSAndroid Build Coastguard Worker {
775*a67afe4dSAndroid Build Coastguard Worker png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
776*a67afe4dSAndroid Build Coastguard Worker name, makepng_error, makepng_warning);
777*a67afe4dSAndroid Build Coastguard Worker volatile png_infop info_ptr = NULL;
778*a67afe4dSAndroid Build Coastguard Worker volatile png_bytep row = NULL;
779*a67afe4dSAndroid Build Coastguard Worker
780*a67afe4dSAndroid Build Coastguard Worker if (png_ptr == NULL)
781*a67afe4dSAndroid Build Coastguard Worker {
782*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: OOM allocating write structure\n");
783*a67afe4dSAndroid Build Coastguard Worker return 1;
784*a67afe4dSAndroid Build Coastguard Worker }
785*a67afe4dSAndroid Build Coastguard Worker
786*a67afe4dSAndroid Build Coastguard Worker if (setjmp(png_jmpbuf(png_ptr)))
787*a67afe4dSAndroid Build Coastguard Worker {
788*a67afe4dSAndroid Build Coastguard Worker png_structp nv_ptr = png_ptr;
789*a67afe4dSAndroid Build Coastguard Worker png_infop nv_info = info_ptr;
790*a67afe4dSAndroid Build Coastguard Worker
791*a67afe4dSAndroid Build Coastguard Worker png_ptr = NULL;
792*a67afe4dSAndroid Build Coastguard Worker info_ptr = NULL;
793*a67afe4dSAndroid Build Coastguard Worker png_destroy_write_struct(&nv_ptr, &nv_info);
794*a67afe4dSAndroid Build Coastguard Worker if (row != NULL) free(row);
795*a67afe4dSAndroid Build Coastguard Worker return 1;
796*a67afe4dSAndroid Build Coastguard Worker }
797*a67afe4dSAndroid Build Coastguard Worker
798*a67afe4dSAndroid Build Coastguard Worker /* Allow benign errors so that we can write PNGs with errors */
799*a67afe4dSAndroid Build Coastguard Worker png_set_benign_errors(png_ptr, 1/*allowed*/);
800*a67afe4dSAndroid Build Coastguard Worker
801*a67afe4dSAndroid Build Coastguard Worker /* Max out the text compression level in an attempt to make the license
802*a67afe4dSAndroid Build Coastguard Worker * small. If --small then do the same for the IDAT.
803*a67afe4dSAndroid Build Coastguard Worker */
804*a67afe4dSAndroid Build Coastguard Worker if (small)
805*a67afe4dSAndroid Build Coastguard Worker png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
806*a67afe4dSAndroid Build Coastguard Worker
807*a67afe4dSAndroid Build Coastguard Worker png_set_text_compression_level(png_ptr, Z_BEST_COMPRESSION);
808*a67afe4dSAndroid Build Coastguard Worker
809*a67afe4dSAndroid Build Coastguard Worker png_init_io(png_ptr, fp);
810*a67afe4dSAndroid Build Coastguard Worker
811*a67afe4dSAndroid Build Coastguard Worker info_ptr = png_create_info_struct(png_ptr);
812*a67afe4dSAndroid Build Coastguard Worker if (info_ptr == NULL)
813*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "OOM allocating info structure");
814*a67afe4dSAndroid Build Coastguard Worker
815*a67afe4dSAndroid Build Coastguard Worker {
816*a67afe4dSAndroid Build Coastguard Worker unsigned int size =
817*a67afe4dSAndroid Build Coastguard Worker image_size_of_type(color_type, bit_depth, colors, small);
818*a67afe4dSAndroid Build Coastguard Worker unsigned int ysize;
819*a67afe4dSAndroid Build Coastguard Worker png_fixed_point real_gamma = 45455; /* For sRGB */
820*a67afe4dSAndroid Build Coastguard Worker png_byte gamma_table[256];
821*a67afe4dSAndroid Build Coastguard Worker double conv;
822*a67afe4dSAndroid Build Coastguard Worker
823*a67afe4dSAndroid Build Coastguard Worker /* Normally images are square, but with 'small' we want to simply generate
824*a67afe4dSAndroid Build Coastguard Worker * all the pixel values, or all that we reasonably can:
825*a67afe4dSAndroid Build Coastguard Worker */
826*a67afe4dSAndroid Build Coastguard Worker if (small)
827*a67afe4dSAndroid Build Coastguard Worker {
828*a67afe4dSAndroid Build Coastguard Worker unsigned int pixel_depth =
829*a67afe4dSAndroid Build Coastguard Worker pixel_depth_of_type(color_type, bit_depth);
830*a67afe4dSAndroid Build Coastguard Worker
831*a67afe4dSAndroid Build Coastguard Worker if (pixel_depth <= 8U)
832*a67afe4dSAndroid Build Coastguard Worker {
833*a67afe4dSAndroid Build Coastguard Worker assert(size == (1U<<pixel_depth));
834*a67afe4dSAndroid Build Coastguard Worker ysize = 1U;
835*a67afe4dSAndroid Build Coastguard Worker }
836*a67afe4dSAndroid Build Coastguard Worker
837*a67afe4dSAndroid Build Coastguard Worker else
838*a67afe4dSAndroid Build Coastguard Worker {
839*a67afe4dSAndroid Build Coastguard Worker assert(size == 256U);
840*a67afe4dSAndroid Build Coastguard Worker ysize = 256U;
841*a67afe4dSAndroid Build Coastguard Worker }
842*a67afe4dSAndroid Build Coastguard Worker }
843*a67afe4dSAndroid Build Coastguard Worker
844*a67afe4dSAndroid Build Coastguard Worker else
845*a67afe4dSAndroid Build Coastguard Worker ysize = size;
846*a67afe4dSAndroid Build Coastguard Worker
847*a67afe4dSAndroid Build Coastguard Worker /* This function uses the libpng values used on read to carry extra
848*a67afe4dSAndroid Build Coastguard Worker * information about the gamma:
849*a67afe4dSAndroid Build Coastguard Worker */
850*a67afe4dSAndroid Build Coastguard Worker if (gamma == PNG_GAMMA_MAC_18)
851*a67afe4dSAndroid Build Coastguard Worker gamma = 65909;
852*a67afe4dSAndroid Build Coastguard Worker
853*a67afe4dSAndroid Build Coastguard Worker else if (gamma > 0 && gamma < 1000)
854*a67afe4dSAndroid Build Coastguard Worker gamma = PNG_FP_1;
855*a67afe4dSAndroid Build Coastguard Worker
856*a67afe4dSAndroid Build Coastguard Worker if (gamma > 0)
857*a67afe4dSAndroid Build Coastguard Worker real_gamma = gamma;
858*a67afe4dSAndroid Build Coastguard Worker
859*a67afe4dSAndroid Build Coastguard Worker {
860*a67afe4dSAndroid Build Coastguard Worker unsigned int i;
861*a67afe4dSAndroid Build Coastguard Worker
862*a67afe4dSAndroid Build Coastguard Worker if (real_gamma == 45455)
863*a67afe4dSAndroid Build Coastguard Worker {
864*a67afe4dSAndroid Build Coastguard Worker for (i=0; i<256; ++i)
865*a67afe4dSAndroid Build Coastguard Worker {
866*a67afe4dSAndroid Build Coastguard Worker gamma_table[i] = (png_byte)i;
867*a67afe4dSAndroid Build Coastguard Worker conv = 1.;
868*a67afe4dSAndroid Build Coastguard Worker }
869*a67afe4dSAndroid Build Coastguard Worker }
870*a67afe4dSAndroid Build Coastguard Worker
871*a67afe4dSAndroid Build Coastguard Worker else
872*a67afe4dSAndroid Build Coastguard Worker {
873*a67afe4dSAndroid Build Coastguard Worker /* Convert 'i' from sRGB (45455) to real_gamma, this makes
874*a67afe4dSAndroid Build Coastguard Worker * the images look the same regardless of the gAMA chunk.
875*a67afe4dSAndroid Build Coastguard Worker */
876*a67afe4dSAndroid Build Coastguard Worker conv = real_gamma;
877*a67afe4dSAndroid Build Coastguard Worker conv /= 45455;
878*a67afe4dSAndroid Build Coastguard Worker
879*a67afe4dSAndroid Build Coastguard Worker gamma_table[0] = 0;
880*a67afe4dSAndroid Build Coastguard Worker
881*a67afe4dSAndroid Build Coastguard Worker for (i=1; i<255; ++i)
882*a67afe4dSAndroid Build Coastguard Worker gamma_table[i] = floorb(pow(i/255.,conv) * 255 + .5);
883*a67afe4dSAndroid Build Coastguard Worker
884*a67afe4dSAndroid Build Coastguard Worker gamma_table[255] = 255;
885*a67afe4dSAndroid Build Coastguard Worker }
886*a67afe4dSAndroid Build Coastguard Worker }
887*a67afe4dSAndroid Build Coastguard Worker
888*a67afe4dSAndroid Build Coastguard Worker png_set_IHDR(png_ptr, info_ptr, size, ysize, bit_depth, color_type,
889*a67afe4dSAndroid Build Coastguard Worker PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
890*a67afe4dSAndroid Build Coastguard Worker
891*a67afe4dSAndroid Build Coastguard Worker if (color_type & PNG_COLOR_MASK_PALETTE)
892*a67afe4dSAndroid Build Coastguard Worker {
893*a67afe4dSAndroid Build Coastguard Worker int npalette;
894*a67afe4dSAndroid Build Coastguard Worker png_color palette[256];
895*a67afe4dSAndroid Build Coastguard Worker png_byte trans[256];
896*a67afe4dSAndroid Build Coastguard Worker
897*a67afe4dSAndroid Build Coastguard Worker npalette = generate_palette(palette, trans, bit_depth, gamma_table,
898*a67afe4dSAndroid Build Coastguard Worker colors);
899*a67afe4dSAndroid Build Coastguard Worker png_set_PLTE(png_ptr, info_ptr, palette, npalette);
900*a67afe4dSAndroid Build Coastguard Worker
901*a67afe4dSAndroid Build Coastguard Worker if (tRNS)
902*a67afe4dSAndroid Build Coastguard Worker png_set_tRNS(png_ptr, info_ptr, trans, npalette-1,
903*a67afe4dSAndroid Build Coastguard Worker NULL/*transparent color*/);
904*a67afe4dSAndroid Build Coastguard Worker
905*a67afe4dSAndroid Build Coastguard Worker /* Reset gamma_table to prevent the image rows being changed */
906*a67afe4dSAndroid Build Coastguard Worker for (npalette=0; npalette<256; ++npalette)
907*a67afe4dSAndroid Build Coastguard Worker gamma_table[npalette] = (png_byte)npalette;
908*a67afe4dSAndroid Build Coastguard Worker }
909*a67afe4dSAndroid Build Coastguard Worker
910*a67afe4dSAndroid Build Coastguard Worker else if (tRNS)
911*a67afe4dSAndroid Build Coastguard Worker {
912*a67afe4dSAndroid Build Coastguard Worker png_color_16 col;
913*a67afe4dSAndroid Build Coastguard Worker
914*a67afe4dSAndroid Build Coastguard Worker col.red = col.green = col.blue = col.gray =
915*a67afe4dSAndroid Build Coastguard Worker 0x0101U & ((1U<<bit_depth)-1U);
916*a67afe4dSAndroid Build Coastguard Worker col.index = 0U;
917*a67afe4dSAndroid Build Coastguard Worker png_set_tRNS(png_ptr, info_ptr, NULL/*trans*/, 1U, &col);
918*a67afe4dSAndroid Build Coastguard Worker }
919*a67afe4dSAndroid Build Coastguard Worker
920*a67afe4dSAndroid Build Coastguard Worker if (gamma == PNG_DEFAULT_sRGB)
921*a67afe4dSAndroid Build Coastguard Worker png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
922*a67afe4dSAndroid Build Coastguard Worker
923*a67afe4dSAndroid Build Coastguard Worker else if (gamma > 0) /* Else don't set color space information */
924*a67afe4dSAndroid Build Coastguard Worker {
925*a67afe4dSAndroid Build Coastguard Worker png_set_gAMA_fixed(png_ptr, info_ptr, real_gamma);
926*a67afe4dSAndroid Build Coastguard Worker
927*a67afe4dSAndroid Build Coastguard Worker /* Just use the sRGB values here. */
928*a67afe4dSAndroid Build Coastguard Worker png_set_cHRM_fixed(png_ptr, info_ptr,
929*a67afe4dSAndroid Build Coastguard Worker /* color x y */
930*a67afe4dSAndroid Build Coastguard Worker /* white */ 31270, 32900,
931*a67afe4dSAndroid Build Coastguard Worker /* red */ 64000, 33000,
932*a67afe4dSAndroid Build Coastguard Worker /* green */ 30000, 60000,
933*a67afe4dSAndroid Build Coastguard Worker /* blue */ 15000, 6000
934*a67afe4dSAndroid Build Coastguard Worker );
935*a67afe4dSAndroid Build Coastguard Worker }
936*a67afe4dSAndroid Build Coastguard Worker
937*a67afe4dSAndroid Build Coastguard Worker /* Insert extra information. */
938*a67afe4dSAndroid Build Coastguard Worker while (insert != NULL)
939*a67afe4dSAndroid Build Coastguard Worker {
940*a67afe4dSAndroid Build Coastguard Worker insert->insert(png_ptr, info_ptr, insert->nparams, insert->parameters);
941*a67afe4dSAndroid Build Coastguard Worker insert = insert->next;
942*a67afe4dSAndroid Build Coastguard Worker }
943*a67afe4dSAndroid Build Coastguard Worker
944*a67afe4dSAndroid Build Coastguard Worker /* Write the file header. */
945*a67afe4dSAndroid Build Coastguard Worker png_write_info(png_ptr, info_ptr);
946*a67afe4dSAndroid Build Coastguard Worker
947*a67afe4dSAndroid Build Coastguard Worker /* Restrict the filters */
948*a67afe4dSAndroid Build Coastguard Worker png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters);
949*a67afe4dSAndroid Build Coastguard Worker
950*a67afe4dSAndroid Build Coastguard Worker {
951*a67afe4dSAndroid Build Coastguard Worker # ifdef PNG_WRITE_INTERLACING_SUPPORTED
952*a67afe4dSAndroid Build Coastguard Worker int passes = png_set_interlace_handling(png_ptr);
953*a67afe4dSAndroid Build Coastguard Worker # else /* !WRITE_INTERLACING */
954*a67afe4dSAndroid Build Coastguard Worker int passes = 1;
955*a67afe4dSAndroid Build Coastguard Worker # endif /* !WRITE_INTERLACING */
956*a67afe4dSAndroid Build Coastguard Worker int pass;
957*a67afe4dSAndroid Build Coastguard Worker size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
958*a67afe4dSAndroid Build Coastguard Worker
959*a67afe4dSAndroid Build Coastguard Worker row = malloc(rowbytes);
960*a67afe4dSAndroid Build Coastguard Worker
961*a67afe4dSAndroid Build Coastguard Worker if (row == NULL)
962*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "OOM allocating row buffer");
963*a67afe4dSAndroid Build Coastguard Worker
964*a67afe4dSAndroid Build Coastguard Worker for (pass = 0; pass < passes; ++pass)
965*a67afe4dSAndroid Build Coastguard Worker {
966*a67afe4dSAndroid Build Coastguard Worker unsigned int y;
967*a67afe4dSAndroid Build Coastguard Worker
968*a67afe4dSAndroid Build Coastguard Worker for (y=0; y<ysize; ++y)
969*a67afe4dSAndroid Build Coastguard Worker {
970*a67afe4dSAndroid Build Coastguard Worker unsigned int row_filters =
971*a67afe4dSAndroid Build Coastguard Worker generate_row(row, rowbytes, y, color_type, bit_depth,
972*a67afe4dSAndroid Build Coastguard Worker gamma_table, conv, colors, small);
973*a67afe4dSAndroid Build Coastguard Worker
974*a67afe4dSAndroid Build Coastguard Worker if (row_filters != 0 && filters == PNG_ALL_FILTERS)
975*a67afe4dSAndroid Build Coastguard Worker png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, row_filters);
976*a67afe4dSAndroid Build Coastguard Worker
977*a67afe4dSAndroid Build Coastguard Worker png_write_row(png_ptr, row);
978*a67afe4dSAndroid Build Coastguard Worker }
979*a67afe4dSAndroid Build Coastguard Worker }
980*a67afe4dSAndroid Build Coastguard Worker }
981*a67afe4dSAndroid Build Coastguard Worker }
982*a67afe4dSAndroid Build Coastguard Worker
983*a67afe4dSAndroid Build Coastguard Worker /* Finish writing the file. */
984*a67afe4dSAndroid Build Coastguard Worker png_write_end(png_ptr, info_ptr);
985*a67afe4dSAndroid Build Coastguard Worker
986*a67afe4dSAndroid Build Coastguard Worker {
987*a67afe4dSAndroid Build Coastguard Worker png_structp nv_ptr = png_ptr;
988*a67afe4dSAndroid Build Coastguard Worker png_infop nv_info = info_ptr;
989*a67afe4dSAndroid Build Coastguard Worker
990*a67afe4dSAndroid Build Coastguard Worker png_ptr = NULL;
991*a67afe4dSAndroid Build Coastguard Worker info_ptr = NULL;
992*a67afe4dSAndroid Build Coastguard Worker png_destroy_write_struct(&nv_ptr, &nv_info);
993*a67afe4dSAndroid Build Coastguard Worker }
994*a67afe4dSAndroid Build Coastguard Worker free(row);
995*a67afe4dSAndroid Build Coastguard Worker return 0;
996*a67afe4dSAndroid Build Coastguard Worker }
997*a67afe4dSAndroid Build Coastguard Worker
998*a67afe4dSAndroid Build Coastguard Worker
999*a67afe4dSAndroid Build Coastguard Worker static size_t
load_file(png_const_charp name,png_bytepp result)1000*a67afe4dSAndroid Build Coastguard Worker load_file(png_const_charp name, png_bytepp result)
1001*a67afe4dSAndroid Build Coastguard Worker {
1002*a67afe4dSAndroid Build Coastguard Worker FILE *fp = tmpfile();
1003*a67afe4dSAndroid Build Coastguard Worker
1004*a67afe4dSAndroid Build Coastguard Worker if (fp != NULL)
1005*a67afe4dSAndroid Build Coastguard Worker {
1006*a67afe4dSAndroid Build Coastguard Worker FILE *ip = fopen(name, "rb");
1007*a67afe4dSAndroid Build Coastguard Worker
1008*a67afe4dSAndroid Build Coastguard Worker if (ip != NULL)
1009*a67afe4dSAndroid Build Coastguard Worker {
1010*a67afe4dSAndroid Build Coastguard Worker size_t total = 0;
1011*a67afe4dSAndroid Build Coastguard Worker int ch;
1012*a67afe4dSAndroid Build Coastguard Worker
1013*a67afe4dSAndroid Build Coastguard Worker for (;;)
1014*a67afe4dSAndroid Build Coastguard Worker {
1015*a67afe4dSAndroid Build Coastguard Worker ch = getc(ip);
1016*a67afe4dSAndroid Build Coastguard Worker if (ch == EOF) break;
1017*a67afe4dSAndroid Build Coastguard Worker putc(ch, fp);
1018*a67afe4dSAndroid Build Coastguard Worker ++total;
1019*a67afe4dSAndroid Build Coastguard Worker }
1020*a67afe4dSAndroid Build Coastguard Worker
1021*a67afe4dSAndroid Build Coastguard Worker if (ferror(ip))
1022*a67afe4dSAndroid Build Coastguard Worker {
1023*a67afe4dSAndroid Build Coastguard Worker perror(name);
1024*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: read error\n", name);
1025*a67afe4dSAndroid Build Coastguard Worker (void)fclose(ip);
1026*a67afe4dSAndroid Build Coastguard Worker }
1027*a67afe4dSAndroid Build Coastguard Worker
1028*a67afe4dSAndroid Build Coastguard Worker else
1029*a67afe4dSAndroid Build Coastguard Worker {
1030*a67afe4dSAndroid Build Coastguard Worker (void)fclose(ip);
1031*a67afe4dSAndroid Build Coastguard Worker
1032*a67afe4dSAndroid Build Coastguard Worker if (ferror(fp))
1033*a67afe4dSAndroid Build Coastguard Worker {
1034*a67afe4dSAndroid Build Coastguard Worker perror("temporary file");
1035*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "temporary file write error\n");
1036*a67afe4dSAndroid Build Coastguard Worker }
1037*a67afe4dSAndroid Build Coastguard Worker
1038*a67afe4dSAndroid Build Coastguard Worker else
1039*a67afe4dSAndroid Build Coastguard Worker {
1040*a67afe4dSAndroid Build Coastguard Worker rewind(fp);
1041*a67afe4dSAndroid Build Coastguard Worker
1042*a67afe4dSAndroid Build Coastguard Worker if (total > 0)
1043*a67afe4dSAndroid Build Coastguard Worker {
1044*a67afe4dSAndroid Build Coastguard Worker /* Round up to a multiple of 4 here to allow an iCCP profile
1045*a67afe4dSAndroid Build Coastguard Worker * to be padded to a 4x boundary.
1046*a67afe4dSAndroid Build Coastguard Worker */
1047*a67afe4dSAndroid Build Coastguard Worker png_bytep data = malloc((total+3)&~3);
1048*a67afe4dSAndroid Build Coastguard Worker
1049*a67afe4dSAndroid Build Coastguard Worker if (data != NULL)
1050*a67afe4dSAndroid Build Coastguard Worker {
1051*a67afe4dSAndroid Build Coastguard Worker size_t new_size = 0;
1052*a67afe4dSAndroid Build Coastguard Worker
1053*a67afe4dSAndroid Build Coastguard Worker for (;;)
1054*a67afe4dSAndroid Build Coastguard Worker {
1055*a67afe4dSAndroid Build Coastguard Worker ch = getc(fp);
1056*a67afe4dSAndroid Build Coastguard Worker if (ch == EOF) break;
1057*a67afe4dSAndroid Build Coastguard Worker data[new_size++] = (png_byte)ch;
1058*a67afe4dSAndroid Build Coastguard Worker }
1059*a67afe4dSAndroid Build Coastguard Worker
1060*a67afe4dSAndroid Build Coastguard Worker if (ferror(fp) || new_size != total)
1061*a67afe4dSAndroid Build Coastguard Worker {
1062*a67afe4dSAndroid Build Coastguard Worker perror("temporary file");
1063*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "temporary file read error\n");
1064*a67afe4dSAndroid Build Coastguard Worker free(data);
1065*a67afe4dSAndroid Build Coastguard Worker }
1066*a67afe4dSAndroid Build Coastguard Worker
1067*a67afe4dSAndroid Build Coastguard Worker else
1068*a67afe4dSAndroid Build Coastguard Worker {
1069*a67afe4dSAndroid Build Coastguard Worker (void)fclose(fp);
1070*a67afe4dSAndroid Build Coastguard Worker *result = data;
1071*a67afe4dSAndroid Build Coastguard Worker return total;
1072*a67afe4dSAndroid Build Coastguard Worker }
1073*a67afe4dSAndroid Build Coastguard Worker }
1074*a67afe4dSAndroid Build Coastguard Worker
1075*a67afe4dSAndroid Build Coastguard Worker else
1076*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: out of memory loading file\n", name);
1077*a67afe4dSAndroid Build Coastguard Worker }
1078*a67afe4dSAndroid Build Coastguard Worker
1079*a67afe4dSAndroid Build Coastguard Worker else
1080*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: empty file\n", name);
1081*a67afe4dSAndroid Build Coastguard Worker }
1082*a67afe4dSAndroid Build Coastguard Worker }
1083*a67afe4dSAndroid Build Coastguard Worker }
1084*a67afe4dSAndroid Build Coastguard Worker
1085*a67afe4dSAndroid Build Coastguard Worker else
1086*a67afe4dSAndroid Build Coastguard Worker {
1087*a67afe4dSAndroid Build Coastguard Worker perror(name);
1088*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: open failed\n", name);
1089*a67afe4dSAndroid Build Coastguard Worker }
1090*a67afe4dSAndroid Build Coastguard Worker
1091*a67afe4dSAndroid Build Coastguard Worker fclose(fp);
1092*a67afe4dSAndroid Build Coastguard Worker }
1093*a67afe4dSAndroid Build Coastguard Worker
1094*a67afe4dSAndroid Build Coastguard Worker else
1095*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: %s: could not open temporary file\n", name);
1096*a67afe4dSAndroid Build Coastguard Worker
1097*a67afe4dSAndroid Build Coastguard Worker exit(1);
1098*a67afe4dSAndroid Build Coastguard Worker return 0;
1099*a67afe4dSAndroid Build Coastguard Worker }
1100*a67afe4dSAndroid Build Coastguard Worker
1101*a67afe4dSAndroid Build Coastguard Worker static size_t
load_fake(png_charp param,png_bytepp profile)1102*a67afe4dSAndroid Build Coastguard Worker load_fake(png_charp param, png_bytepp profile)
1103*a67afe4dSAndroid Build Coastguard Worker {
1104*a67afe4dSAndroid Build Coastguard Worker char *endptr = NULL;
1105*a67afe4dSAndroid Build Coastguard Worker uint64_t size = strtoull(param, &endptr, 0/*base*/);
1106*a67afe4dSAndroid Build Coastguard Worker
1107*a67afe4dSAndroid Build Coastguard Worker /* The 'fake' format is <number>*[string] */
1108*a67afe4dSAndroid Build Coastguard Worker if (endptr != NULL && *endptr == '*')
1109*a67afe4dSAndroid Build Coastguard Worker {
1110*a67afe4dSAndroid Build Coastguard Worker size_t len = strlen(++endptr);
1111*a67afe4dSAndroid Build Coastguard Worker size_t result = (size_t)size;
1112*a67afe4dSAndroid Build Coastguard Worker
1113*a67afe4dSAndroid Build Coastguard Worker if (len == 0) len = 1; /* capture the terminating '\0' */
1114*a67afe4dSAndroid Build Coastguard Worker
1115*a67afe4dSAndroid Build Coastguard Worker /* Now repeat that string to fill 'size' bytes. */
1116*a67afe4dSAndroid Build Coastguard Worker if (result == size && (*profile = malloc(result)) != NULL)
1117*a67afe4dSAndroid Build Coastguard Worker {
1118*a67afe4dSAndroid Build Coastguard Worker png_bytep out = *profile;
1119*a67afe4dSAndroid Build Coastguard Worker
1120*a67afe4dSAndroid Build Coastguard Worker if (len == 1)
1121*a67afe4dSAndroid Build Coastguard Worker memset(out, *endptr, result);
1122*a67afe4dSAndroid Build Coastguard Worker
1123*a67afe4dSAndroid Build Coastguard Worker else
1124*a67afe4dSAndroid Build Coastguard Worker {
1125*a67afe4dSAndroid Build Coastguard Worker while (size >= len)
1126*a67afe4dSAndroid Build Coastguard Worker {
1127*a67afe4dSAndroid Build Coastguard Worker memcpy(out, endptr, len);
1128*a67afe4dSAndroid Build Coastguard Worker out += len;
1129*a67afe4dSAndroid Build Coastguard Worker size -= len;
1130*a67afe4dSAndroid Build Coastguard Worker }
1131*a67afe4dSAndroid Build Coastguard Worker memcpy(out, endptr, size);
1132*a67afe4dSAndroid Build Coastguard Worker }
1133*a67afe4dSAndroid Build Coastguard Worker
1134*a67afe4dSAndroid Build Coastguard Worker return result;
1135*a67afe4dSAndroid Build Coastguard Worker }
1136*a67afe4dSAndroid Build Coastguard Worker
1137*a67afe4dSAndroid Build Coastguard Worker else
1138*a67afe4dSAndroid Build Coastguard Worker {
1139*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: size exceeds system limits\n", param);
1140*a67afe4dSAndroid Build Coastguard Worker exit(1);
1141*a67afe4dSAndroid Build Coastguard Worker }
1142*a67afe4dSAndroid Build Coastguard Worker }
1143*a67afe4dSAndroid Build Coastguard Worker
1144*a67afe4dSAndroid Build Coastguard Worker return 0;
1145*a67afe4dSAndroid Build Coastguard Worker }
1146*a67afe4dSAndroid Build Coastguard Worker
1147*a67afe4dSAndroid Build Coastguard Worker static void
check_param_count(int nparams,int expect)1148*a67afe4dSAndroid Build Coastguard Worker check_param_count(int nparams, int expect)
1149*a67afe4dSAndroid Build Coastguard Worker {
1150*a67afe4dSAndroid Build Coastguard Worker if (nparams != expect)
1151*a67afe4dSAndroid Build Coastguard Worker {
1152*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "bad parameter count (internal error)\n");
1153*a67afe4dSAndroid Build Coastguard Worker exit(1);
1154*a67afe4dSAndroid Build Coastguard Worker }
1155*a67afe4dSAndroid Build Coastguard Worker }
1156*a67afe4dSAndroid Build Coastguard Worker
1157*a67afe4dSAndroid Build Coastguard Worker static void
insert_iCCP(png_structp png_ptr,png_infop info_ptr,int nparams,png_charpp params)1158*a67afe4dSAndroid Build Coastguard Worker insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams,
1159*a67afe4dSAndroid Build Coastguard Worker png_charpp params)
1160*a67afe4dSAndroid Build Coastguard Worker {
1161*a67afe4dSAndroid Build Coastguard Worker png_bytep profile = NULL;
1162*a67afe4dSAndroid Build Coastguard Worker png_uint_32 proflen = 0;
1163*a67afe4dSAndroid Build Coastguard Worker int result;
1164*a67afe4dSAndroid Build Coastguard Worker
1165*a67afe4dSAndroid Build Coastguard Worker check_param_count(nparams, 2);
1166*a67afe4dSAndroid Build Coastguard Worker
1167*a67afe4dSAndroid Build Coastguard Worker switch (params[1][0])
1168*a67afe4dSAndroid Build Coastguard Worker {
1169*a67afe4dSAndroid Build Coastguard Worker case '<':
1170*a67afe4dSAndroid Build Coastguard Worker {
1171*a67afe4dSAndroid Build Coastguard Worker size_t filelen = load_file(params[1]+1, &profile);
1172*a67afe4dSAndroid Build Coastguard Worker if (filelen > 0xfffffffc) /* Maximum profile length */
1173*a67afe4dSAndroid Build Coastguard Worker {
1174*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n",
1175*a67afe4dSAndroid Build Coastguard Worker params[1]+1, (unsigned long)filelen);
1176*a67afe4dSAndroid Build Coastguard Worker exit(1);
1177*a67afe4dSAndroid Build Coastguard Worker }
1178*a67afe4dSAndroid Build Coastguard Worker
1179*a67afe4dSAndroid Build Coastguard Worker proflen = (png_uint_32)filelen;
1180*a67afe4dSAndroid Build Coastguard Worker }
1181*a67afe4dSAndroid Build Coastguard Worker break;
1182*a67afe4dSAndroid Build Coastguard Worker
1183*a67afe4dSAndroid Build Coastguard Worker case '0': case '1': case '2': case '3': case '4':
1184*a67afe4dSAndroid Build Coastguard Worker case '5': case '6': case '7': case '8': case '9':
1185*a67afe4dSAndroid Build Coastguard Worker {
1186*a67afe4dSAndroid Build Coastguard Worker size_t fake_len = load_fake(params[1], &profile);
1187*a67afe4dSAndroid Build Coastguard Worker
1188*a67afe4dSAndroid Build Coastguard Worker if (fake_len > 0) /* else a simple parameter */
1189*a67afe4dSAndroid Build Coastguard Worker {
1190*a67afe4dSAndroid Build Coastguard Worker if (fake_len > 0xffffffff) /* Maximum profile length */
1191*a67afe4dSAndroid Build Coastguard Worker {
1192*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr,
1193*a67afe4dSAndroid Build Coastguard Worker "%s: fake data too long (%lu) for an ICC profile\n",
1194*a67afe4dSAndroid Build Coastguard Worker params[1], (unsigned long)fake_len);
1195*a67afe4dSAndroid Build Coastguard Worker exit(1);
1196*a67afe4dSAndroid Build Coastguard Worker }
1197*a67afe4dSAndroid Build Coastguard Worker proflen = (png_uint_32)(fake_len & ~3U);
1198*a67afe4dSAndroid Build Coastguard Worker /* Always fix up the profile length. */
1199*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(profile, proflen);
1200*a67afe4dSAndroid Build Coastguard Worker break;
1201*a67afe4dSAndroid Build Coastguard Worker }
1202*a67afe4dSAndroid Build Coastguard Worker }
1203*a67afe4dSAndroid Build Coastguard Worker
1204*a67afe4dSAndroid Build Coastguard Worker default:
1205*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "--insert iCCP \"%s\": unrecognized\n", params[1]);
1206*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, " use '<' to read a file: \"<filename\"\n");
1207*a67afe4dSAndroid Build Coastguard Worker exit(1);
1208*a67afe4dSAndroid Build Coastguard Worker }
1209*a67afe4dSAndroid Build Coastguard Worker
1210*a67afe4dSAndroid Build Coastguard Worker result = 1;
1211*a67afe4dSAndroid Build Coastguard Worker
1212*a67afe4dSAndroid Build Coastguard Worker if (proflen & 3)
1213*a67afe4dSAndroid Build Coastguard Worker {
1214*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr,
1215*a67afe4dSAndroid Build Coastguard Worker "makepng: --insert iCCP %s: profile length made a multiple of 4\n",
1216*a67afe4dSAndroid Build Coastguard Worker params[1]);
1217*a67afe4dSAndroid Build Coastguard Worker
1218*a67afe4dSAndroid Build Coastguard Worker /* load_file allocates extra space for this padding, the ICC spec requires
1219*a67afe4dSAndroid Build Coastguard Worker * padding with zero bytes.
1220*a67afe4dSAndroid Build Coastguard Worker */
1221*a67afe4dSAndroid Build Coastguard Worker while (proflen & 3)
1222*a67afe4dSAndroid Build Coastguard Worker profile[proflen++] = 0;
1223*a67afe4dSAndroid Build Coastguard Worker }
1224*a67afe4dSAndroid Build Coastguard Worker
1225*a67afe4dSAndroid Build Coastguard Worker if (profile != NULL && proflen > 3)
1226*a67afe4dSAndroid Build Coastguard Worker {
1227*a67afe4dSAndroid Build Coastguard Worker png_uint_32 prof_header = png_get_uint_32(profile);
1228*a67afe4dSAndroid Build Coastguard Worker
1229*a67afe4dSAndroid Build Coastguard Worker if (prof_header != proflen)
1230*a67afe4dSAndroid Build Coastguard Worker {
1231*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "--insert iCCP %s: profile length field wrong:\n",
1232*a67afe4dSAndroid Build Coastguard Worker params[1]);
1233*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, " actual %lu, recorded value %lu (corrected)\n",
1234*a67afe4dSAndroid Build Coastguard Worker (unsigned long)proflen, (unsigned long)prof_header);
1235*a67afe4dSAndroid Build Coastguard Worker png_save_uint_32(profile, proflen);
1236*a67afe4dSAndroid Build Coastguard Worker }
1237*a67afe4dSAndroid Build Coastguard Worker }
1238*a67afe4dSAndroid Build Coastguard Worker
1239*a67afe4dSAndroid Build Coastguard Worker if (result && profile != NULL && proflen >=4)
1240*a67afe4dSAndroid Build Coastguard Worker png_set_iCCP(png_ptr, info_ptr, params[0], PNG_COMPRESSION_TYPE_BASE,
1241*a67afe4dSAndroid Build Coastguard Worker profile, proflen);
1242*a67afe4dSAndroid Build Coastguard Worker
1243*a67afe4dSAndroid Build Coastguard Worker if (profile)
1244*a67afe4dSAndroid Build Coastguard Worker free(profile);
1245*a67afe4dSAndroid Build Coastguard Worker
1246*a67afe4dSAndroid Build Coastguard Worker if (!result)
1247*a67afe4dSAndroid Build Coastguard Worker exit(1);
1248*a67afe4dSAndroid Build Coastguard Worker }
1249*a67afe4dSAndroid Build Coastguard Worker
1250*a67afe4dSAndroid Build Coastguard Worker static void
clear_text(png_text * text,png_charp keyword)1251*a67afe4dSAndroid Build Coastguard Worker clear_text(png_text *text, png_charp keyword)
1252*a67afe4dSAndroid Build Coastguard Worker {
1253*a67afe4dSAndroid Build Coastguard Worker text->compression = -1; /* none */
1254*a67afe4dSAndroid Build Coastguard Worker text->key = keyword;
1255*a67afe4dSAndroid Build Coastguard Worker text->text = NULL;
1256*a67afe4dSAndroid Build Coastguard Worker text->text_length = 0; /* libpng calculates this */
1257*a67afe4dSAndroid Build Coastguard Worker text->itxt_length = 0; /* libpng calculates this */
1258*a67afe4dSAndroid Build Coastguard Worker text->lang = NULL;
1259*a67afe4dSAndroid Build Coastguard Worker text->lang_key = NULL;
1260*a67afe4dSAndroid Build Coastguard Worker }
1261*a67afe4dSAndroid Build Coastguard Worker
1262*a67afe4dSAndroid Build Coastguard Worker static void
set_text(png_structp png_ptr,png_infop info_ptr,png_textp text,png_charp param)1263*a67afe4dSAndroid Build Coastguard Worker set_text(png_structp png_ptr, png_infop info_ptr, png_textp text,
1264*a67afe4dSAndroid Build Coastguard Worker png_charp param)
1265*a67afe4dSAndroid Build Coastguard Worker {
1266*a67afe4dSAndroid Build Coastguard Worker switch (param[0])
1267*a67afe4dSAndroid Build Coastguard Worker {
1268*a67afe4dSAndroid Build Coastguard Worker case '<':
1269*a67afe4dSAndroid Build Coastguard Worker {
1270*a67afe4dSAndroid Build Coastguard Worker png_bytep file = NULL;
1271*a67afe4dSAndroid Build Coastguard Worker
1272*a67afe4dSAndroid Build Coastguard Worker text->text_length = load_file(param+1, &file);
1273*a67afe4dSAndroid Build Coastguard Worker text->text = (png_charp)file;
1274*a67afe4dSAndroid Build Coastguard Worker }
1275*a67afe4dSAndroid Build Coastguard Worker break;
1276*a67afe4dSAndroid Build Coastguard Worker
1277*a67afe4dSAndroid Build Coastguard Worker case '0': case '1': case '2': case '3': case '4':
1278*a67afe4dSAndroid Build Coastguard Worker case '5': case '6': case '7': case '8': case '9':
1279*a67afe4dSAndroid Build Coastguard Worker {
1280*a67afe4dSAndroid Build Coastguard Worker png_bytep data = NULL;
1281*a67afe4dSAndroid Build Coastguard Worker size_t fake_len = load_fake(param, &data);
1282*a67afe4dSAndroid Build Coastguard Worker
1283*a67afe4dSAndroid Build Coastguard Worker if (fake_len > 0) /* else a simple parameter */
1284*a67afe4dSAndroid Build Coastguard Worker {
1285*a67afe4dSAndroid Build Coastguard Worker text->text_length = fake_len;
1286*a67afe4dSAndroid Build Coastguard Worker text->text = (png_charp)data;
1287*a67afe4dSAndroid Build Coastguard Worker break;
1288*a67afe4dSAndroid Build Coastguard Worker }
1289*a67afe4dSAndroid Build Coastguard Worker }
1290*a67afe4dSAndroid Build Coastguard Worker
1291*a67afe4dSAndroid Build Coastguard Worker default:
1292*a67afe4dSAndroid Build Coastguard Worker text->text = param;
1293*a67afe4dSAndroid Build Coastguard Worker break;
1294*a67afe4dSAndroid Build Coastguard Worker }
1295*a67afe4dSAndroid Build Coastguard Worker
1296*a67afe4dSAndroid Build Coastguard Worker png_set_text(png_ptr, info_ptr, text, 1);
1297*a67afe4dSAndroid Build Coastguard Worker
1298*a67afe4dSAndroid Build Coastguard Worker if (text->text != param)
1299*a67afe4dSAndroid Build Coastguard Worker free(text->text);
1300*a67afe4dSAndroid Build Coastguard Worker }
1301*a67afe4dSAndroid Build Coastguard Worker
1302*a67afe4dSAndroid Build Coastguard Worker static void
insert_tEXt(png_structp png_ptr,png_infop info_ptr,int nparams,png_charpp params)1303*a67afe4dSAndroid Build Coastguard Worker insert_tEXt(png_structp png_ptr, png_infop info_ptr, int nparams,
1304*a67afe4dSAndroid Build Coastguard Worker png_charpp params)
1305*a67afe4dSAndroid Build Coastguard Worker {
1306*a67afe4dSAndroid Build Coastguard Worker png_text text;
1307*a67afe4dSAndroid Build Coastguard Worker
1308*a67afe4dSAndroid Build Coastguard Worker check_param_count(nparams, 2);
1309*a67afe4dSAndroid Build Coastguard Worker clear_text(&text, params[0]);
1310*a67afe4dSAndroid Build Coastguard Worker set_text(png_ptr, info_ptr, &text, params[1]);
1311*a67afe4dSAndroid Build Coastguard Worker }
1312*a67afe4dSAndroid Build Coastguard Worker
1313*a67afe4dSAndroid Build Coastguard Worker static void
insert_zTXt(png_structp png_ptr,png_infop info_ptr,int nparams,png_charpp params)1314*a67afe4dSAndroid Build Coastguard Worker insert_zTXt(png_structp png_ptr, png_infop info_ptr, int nparams,
1315*a67afe4dSAndroid Build Coastguard Worker png_charpp params)
1316*a67afe4dSAndroid Build Coastguard Worker {
1317*a67afe4dSAndroid Build Coastguard Worker png_text text;
1318*a67afe4dSAndroid Build Coastguard Worker
1319*a67afe4dSAndroid Build Coastguard Worker check_param_count(nparams, 2);
1320*a67afe4dSAndroid Build Coastguard Worker clear_text(&text, params[0]);
1321*a67afe4dSAndroid Build Coastguard Worker text.compression = 0; /* deflate */
1322*a67afe4dSAndroid Build Coastguard Worker set_text(png_ptr, info_ptr, &text, params[1]);
1323*a67afe4dSAndroid Build Coastguard Worker }
1324*a67afe4dSAndroid Build Coastguard Worker
1325*a67afe4dSAndroid Build Coastguard Worker static void
insert_iTXt(png_structp png_ptr,png_infop info_ptr,int nparams,png_charpp params)1326*a67afe4dSAndroid Build Coastguard Worker insert_iTXt(png_structp png_ptr, png_infop info_ptr, int nparams,
1327*a67afe4dSAndroid Build Coastguard Worker png_charpp params)
1328*a67afe4dSAndroid Build Coastguard Worker {
1329*a67afe4dSAndroid Build Coastguard Worker png_text text;
1330*a67afe4dSAndroid Build Coastguard Worker
1331*a67afe4dSAndroid Build Coastguard Worker check_param_count(nparams, 4);
1332*a67afe4dSAndroid Build Coastguard Worker clear_text(&text, params[0]);
1333*a67afe4dSAndroid Build Coastguard Worker text.compression = 2; /* iTXt + deflate */
1334*a67afe4dSAndroid Build Coastguard Worker text.lang = params[1];/* language tag */
1335*a67afe4dSAndroid Build Coastguard Worker text.lang_key = params[2]; /* translated keyword */
1336*a67afe4dSAndroid Build Coastguard Worker set_text(png_ptr, info_ptr, &text, params[3]);
1337*a67afe4dSAndroid Build Coastguard Worker }
1338*a67afe4dSAndroid Build Coastguard Worker
1339*a67afe4dSAndroid Build Coastguard Worker static void
insert_hIST(png_structp png_ptr,png_infop info_ptr,int nparams,png_charpp params)1340*a67afe4dSAndroid Build Coastguard Worker insert_hIST(png_structp png_ptr, png_infop info_ptr, int nparams,
1341*a67afe4dSAndroid Build Coastguard Worker png_charpp params)
1342*a67afe4dSAndroid Build Coastguard Worker {
1343*a67afe4dSAndroid Build Coastguard Worker int i;
1344*a67afe4dSAndroid Build Coastguard Worker png_uint_16 freq[256];
1345*a67afe4dSAndroid Build Coastguard Worker
1346*a67afe4dSAndroid Build Coastguard Worker /* libpng takes the count from the PLTE count; we don't check it here but we
1347*a67afe4dSAndroid Build Coastguard Worker * do set the array to 0 for unspecified entries.
1348*a67afe4dSAndroid Build Coastguard Worker */
1349*a67afe4dSAndroid Build Coastguard Worker memset(freq, 0, sizeof freq);
1350*a67afe4dSAndroid Build Coastguard Worker for (i=0; i<nparams; ++i)
1351*a67afe4dSAndroid Build Coastguard Worker {
1352*a67afe4dSAndroid Build Coastguard Worker char *endptr = NULL;
1353*a67afe4dSAndroid Build Coastguard Worker unsigned long int l = strtoul(params[i], &endptr, 0/*base*/);
1354*a67afe4dSAndroid Build Coastguard Worker
1355*a67afe4dSAndroid Build Coastguard Worker if (params[i][0] && *endptr == 0 && l <= 65535)
1356*a67afe4dSAndroid Build Coastguard Worker freq[i] = (png_uint_16)l;
1357*a67afe4dSAndroid Build Coastguard Worker
1358*a67afe4dSAndroid Build Coastguard Worker else
1359*a67afe4dSAndroid Build Coastguard Worker {
1360*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "hIST[%d]: %s: invalid frequency\n", i, params[i]);
1361*a67afe4dSAndroid Build Coastguard Worker exit(1);
1362*a67afe4dSAndroid Build Coastguard Worker }
1363*a67afe4dSAndroid Build Coastguard Worker }
1364*a67afe4dSAndroid Build Coastguard Worker
1365*a67afe4dSAndroid Build Coastguard Worker png_set_hIST(png_ptr, info_ptr, freq);
1366*a67afe4dSAndroid Build Coastguard Worker }
1367*a67afe4dSAndroid Build Coastguard Worker
1368*a67afe4dSAndroid Build Coastguard Worker static png_byte
bval(png_const_structrp png_ptr,png_charp param,unsigned int maxval)1369*a67afe4dSAndroid Build Coastguard Worker bval(png_const_structrp png_ptr, png_charp param, unsigned int maxval)
1370*a67afe4dSAndroid Build Coastguard Worker {
1371*a67afe4dSAndroid Build Coastguard Worker char *endptr = NULL;
1372*a67afe4dSAndroid Build Coastguard Worker unsigned long int l = strtoul(param, &endptr, 0/*base*/);
1373*a67afe4dSAndroid Build Coastguard Worker
1374*a67afe4dSAndroid Build Coastguard Worker if (param[0] && *endptr == 0 && l <= maxval)
1375*a67afe4dSAndroid Build Coastguard Worker return (png_byte)l;
1376*a67afe4dSAndroid Build Coastguard Worker
1377*a67afe4dSAndroid Build Coastguard Worker else
1378*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "sBIT: invalid sBIT value");
1379*a67afe4dSAndroid Build Coastguard Worker }
1380*a67afe4dSAndroid Build Coastguard Worker
1381*a67afe4dSAndroid Build Coastguard Worker static void
insert_sBIT(png_structp png_ptr,png_infop info_ptr,int nparams,png_charpp params)1382*a67afe4dSAndroid Build Coastguard Worker insert_sBIT(png_structp png_ptr, png_infop info_ptr, int nparams,
1383*a67afe4dSAndroid Build Coastguard Worker png_charpp params)
1384*a67afe4dSAndroid Build Coastguard Worker {
1385*a67afe4dSAndroid Build Coastguard Worker int ct = png_get_color_type(png_ptr, info_ptr);
1386*a67afe4dSAndroid Build Coastguard Worker int c = (ct & PNG_COLOR_MASK_COLOR ? 3 : 1) +
1387*a67afe4dSAndroid Build Coastguard Worker (ct & PNG_COLOR_MASK_ALPHA ? 1 : 0);
1388*a67afe4dSAndroid Build Coastguard Worker unsigned int maxval =
1389*a67afe4dSAndroid Build Coastguard Worker ct & PNG_COLOR_MASK_PALETTE ? 8U : png_get_bit_depth(png_ptr, info_ptr);
1390*a67afe4dSAndroid Build Coastguard Worker png_color_8 sBIT;
1391*a67afe4dSAndroid Build Coastguard Worker
1392*a67afe4dSAndroid Build Coastguard Worker if (nparams != c)
1393*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "sBIT: incorrect parameter count");
1394*a67afe4dSAndroid Build Coastguard Worker
1395*a67afe4dSAndroid Build Coastguard Worker if (ct & PNG_COLOR_MASK_COLOR)
1396*a67afe4dSAndroid Build Coastguard Worker {
1397*a67afe4dSAndroid Build Coastguard Worker sBIT.red = bval(png_ptr, params[0], maxval);
1398*a67afe4dSAndroid Build Coastguard Worker sBIT.green = bval(png_ptr, params[1], maxval);
1399*a67afe4dSAndroid Build Coastguard Worker sBIT.blue = bval(png_ptr, params[2], maxval);
1400*a67afe4dSAndroid Build Coastguard Worker sBIT.gray = 42;
1401*a67afe4dSAndroid Build Coastguard Worker }
1402*a67afe4dSAndroid Build Coastguard Worker
1403*a67afe4dSAndroid Build Coastguard Worker else
1404*a67afe4dSAndroid Build Coastguard Worker {
1405*a67afe4dSAndroid Build Coastguard Worker sBIT.red = sBIT.green = sBIT.blue = 42;
1406*a67afe4dSAndroid Build Coastguard Worker sBIT.gray = bval(png_ptr, params[0], maxval);
1407*a67afe4dSAndroid Build Coastguard Worker }
1408*a67afe4dSAndroid Build Coastguard Worker
1409*a67afe4dSAndroid Build Coastguard Worker if (ct & PNG_COLOR_MASK_ALPHA)
1410*a67afe4dSAndroid Build Coastguard Worker sBIT.alpha = bval(png_ptr, params[nparams-1], maxval);
1411*a67afe4dSAndroid Build Coastguard Worker
1412*a67afe4dSAndroid Build Coastguard Worker else
1413*a67afe4dSAndroid Build Coastguard Worker sBIT.alpha = 42;
1414*a67afe4dSAndroid Build Coastguard Worker
1415*a67afe4dSAndroid Build Coastguard Worker png_set_sBIT(png_ptr, info_ptr, &sBIT);
1416*a67afe4dSAndroid Build Coastguard Worker }
1417*a67afe4dSAndroid Build Coastguard Worker
1418*a67afe4dSAndroid Build Coastguard Worker #if 0
1419*a67afe4dSAndroid Build Coastguard Worker static void
1420*a67afe4dSAndroid Build Coastguard Worker insert_sPLT(png_structp png_ptr, png_infop info_ptr, int nparams, png_charpp params)
1421*a67afe4dSAndroid Build Coastguard Worker {
1422*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "insert sPLT: NYI\n");
1423*a67afe4dSAndroid Build Coastguard Worker }
1424*a67afe4dSAndroid Build Coastguard Worker #endif
1425*a67afe4dSAndroid Build Coastguard Worker
1426*a67afe4dSAndroid Build Coastguard Worker static int
find_parameters(png_const_charp what,png_charp param,png_charp * list,int nparams)1427*a67afe4dSAndroid Build Coastguard Worker find_parameters(png_const_charp what, png_charp param, png_charp *list,
1428*a67afe4dSAndroid Build Coastguard Worker int nparams)
1429*a67afe4dSAndroid Build Coastguard Worker {
1430*a67afe4dSAndroid Build Coastguard Worker /* Parameters are separated by '\n' or ':' characters, up to nparams are
1431*a67afe4dSAndroid Build Coastguard Worker * accepted (more is an error) and the number found is returned.
1432*a67afe4dSAndroid Build Coastguard Worker */
1433*a67afe4dSAndroid Build Coastguard Worker int i;
1434*a67afe4dSAndroid Build Coastguard Worker for (i=0; *param && i<nparams; ++i)
1435*a67afe4dSAndroid Build Coastguard Worker {
1436*a67afe4dSAndroid Build Coastguard Worker list[i] = param;
1437*a67afe4dSAndroid Build Coastguard Worker while (*++param)
1438*a67afe4dSAndroid Build Coastguard Worker {
1439*a67afe4dSAndroid Build Coastguard Worker if (*param == '\n' || *param == ':')
1440*a67afe4dSAndroid Build Coastguard Worker {
1441*a67afe4dSAndroid Build Coastguard Worker *param++ = 0; /* Terminate last parameter */
1442*a67afe4dSAndroid Build Coastguard Worker break; /* And start a new one. */
1443*a67afe4dSAndroid Build Coastguard Worker }
1444*a67afe4dSAndroid Build Coastguard Worker }
1445*a67afe4dSAndroid Build Coastguard Worker }
1446*a67afe4dSAndroid Build Coastguard Worker
1447*a67afe4dSAndroid Build Coastguard Worker if (*param)
1448*a67afe4dSAndroid Build Coastguard Worker {
1449*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "--insert %s: too many parameters (%s)\n", what, param);
1450*a67afe4dSAndroid Build Coastguard Worker exit(1);
1451*a67afe4dSAndroid Build Coastguard Worker }
1452*a67afe4dSAndroid Build Coastguard Worker
1453*a67afe4dSAndroid Build Coastguard Worker list[i] = NULL; /* terminates list */
1454*a67afe4dSAndroid Build Coastguard Worker return i; /* number of parameters filled in */
1455*a67afe4dSAndroid Build Coastguard Worker }
1456*a67afe4dSAndroid Build Coastguard Worker
1457*a67afe4dSAndroid Build Coastguard Worker static void
bad_parameter_count(png_const_charp what,int nparams)1458*a67afe4dSAndroid Build Coastguard Worker bad_parameter_count(png_const_charp what, int nparams)
1459*a67afe4dSAndroid Build Coastguard Worker {
1460*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "--insert %s: bad parameter count %d\n", what, nparams);
1461*a67afe4dSAndroid Build Coastguard Worker exit(1);
1462*a67afe4dSAndroid Build Coastguard Worker }
1463*a67afe4dSAndroid Build Coastguard Worker
1464*a67afe4dSAndroid Build Coastguard Worker static chunk_insert *
make_insert(png_const_charp what,void (* insert)(png_structp,png_infop,int,png_charpp),int nparams,png_charpp list)1465*a67afe4dSAndroid Build Coastguard Worker make_insert(png_const_charp what,
1466*a67afe4dSAndroid Build Coastguard Worker void (*insert)(png_structp, png_infop, int, png_charpp),
1467*a67afe4dSAndroid Build Coastguard Worker int nparams, png_charpp list)
1468*a67afe4dSAndroid Build Coastguard Worker {
1469*a67afe4dSAndroid Build Coastguard Worker int i;
1470*a67afe4dSAndroid Build Coastguard Worker chunk_insert *cip;
1471*a67afe4dSAndroid Build Coastguard Worker
1472*a67afe4dSAndroid Build Coastguard Worker cip = malloc(offsetof(chunk_insert,parameters) +
1473*a67afe4dSAndroid Build Coastguard Worker nparams * sizeof (png_charp));
1474*a67afe4dSAndroid Build Coastguard Worker
1475*a67afe4dSAndroid Build Coastguard Worker if (cip == NULL)
1476*a67afe4dSAndroid Build Coastguard Worker {
1477*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "--insert %s: out of memory allocating %d parameters\n",
1478*a67afe4dSAndroid Build Coastguard Worker what, nparams);
1479*a67afe4dSAndroid Build Coastguard Worker exit(1);
1480*a67afe4dSAndroid Build Coastguard Worker }
1481*a67afe4dSAndroid Build Coastguard Worker
1482*a67afe4dSAndroid Build Coastguard Worker cip->next = NULL;
1483*a67afe4dSAndroid Build Coastguard Worker cip->insert = insert;
1484*a67afe4dSAndroid Build Coastguard Worker cip->nparams = nparams;
1485*a67afe4dSAndroid Build Coastguard Worker for (i=0; i<nparams; ++i)
1486*a67afe4dSAndroid Build Coastguard Worker cip->parameters[i] = list[i];
1487*a67afe4dSAndroid Build Coastguard Worker
1488*a67afe4dSAndroid Build Coastguard Worker return cip;
1489*a67afe4dSAndroid Build Coastguard Worker }
1490*a67afe4dSAndroid Build Coastguard Worker
1491*a67afe4dSAndroid Build Coastguard Worker static chunk_insert *
find_insert(png_const_charp what,png_charp param)1492*a67afe4dSAndroid Build Coastguard Worker find_insert(png_const_charp what, png_charp param)
1493*a67afe4dSAndroid Build Coastguard Worker {
1494*a67afe4dSAndroid Build Coastguard Worker png_uint_32 chunk = 0;
1495*a67afe4dSAndroid Build Coastguard Worker png_charp parameter_list[1024];
1496*a67afe4dSAndroid Build Coastguard Worker int i, nparams;
1497*a67afe4dSAndroid Build Coastguard Worker
1498*a67afe4dSAndroid Build Coastguard Worker /* Assemble the chunk name */
1499*a67afe4dSAndroid Build Coastguard Worker for (i=0; i<4; ++i)
1500*a67afe4dSAndroid Build Coastguard Worker {
1501*a67afe4dSAndroid Build Coastguard Worker char ch = what[i];
1502*a67afe4dSAndroid Build Coastguard Worker
1503*a67afe4dSAndroid Build Coastguard Worker if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122))
1504*a67afe4dSAndroid Build Coastguard Worker chunk = (chunk << 8) + what[i];
1505*a67afe4dSAndroid Build Coastguard Worker
1506*a67afe4dSAndroid Build Coastguard Worker else
1507*a67afe4dSAndroid Build Coastguard Worker break;
1508*a67afe4dSAndroid Build Coastguard Worker }
1509*a67afe4dSAndroid Build Coastguard Worker
1510*a67afe4dSAndroid Build Coastguard Worker if (i < 4 || what[4] != 0)
1511*a67afe4dSAndroid Build Coastguard Worker {
1512*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng --insert \"%s\": invalid chunk name\n", what);
1513*a67afe4dSAndroid Build Coastguard Worker exit(1);
1514*a67afe4dSAndroid Build Coastguard Worker }
1515*a67afe4dSAndroid Build Coastguard Worker
1516*a67afe4dSAndroid Build Coastguard Worker /* Assemble the parameter list. */
1517*a67afe4dSAndroid Build Coastguard Worker nparams = find_parameters(what, param, parameter_list, 1024);
1518*a67afe4dSAndroid Build Coastguard Worker
1519*a67afe4dSAndroid Build Coastguard Worker # define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d))
1520*a67afe4dSAndroid Build Coastguard Worker
1521*a67afe4dSAndroid Build Coastguard Worker switch (chunk)
1522*a67afe4dSAndroid Build Coastguard Worker {
1523*a67afe4dSAndroid Build Coastguard Worker case CHUNK(105,67,67,80): /* iCCP */
1524*a67afe4dSAndroid Build Coastguard Worker if (nparams == 2)
1525*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_iCCP, nparams, parameter_list);
1526*a67afe4dSAndroid Build Coastguard Worker break;
1527*a67afe4dSAndroid Build Coastguard Worker
1528*a67afe4dSAndroid Build Coastguard Worker case CHUNK(116,69,88,116): /* tEXt */
1529*a67afe4dSAndroid Build Coastguard Worker if (nparams == 2)
1530*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_tEXt, nparams, parameter_list);
1531*a67afe4dSAndroid Build Coastguard Worker break;
1532*a67afe4dSAndroid Build Coastguard Worker
1533*a67afe4dSAndroid Build Coastguard Worker case CHUNK(122,84,88,116): /* zTXt */
1534*a67afe4dSAndroid Build Coastguard Worker if (nparams == 2)
1535*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_zTXt, nparams, parameter_list);
1536*a67afe4dSAndroid Build Coastguard Worker break;
1537*a67afe4dSAndroid Build Coastguard Worker
1538*a67afe4dSAndroid Build Coastguard Worker case CHUNK(105,84,88,116): /* iTXt */
1539*a67afe4dSAndroid Build Coastguard Worker if (nparams == 4)
1540*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_iTXt, nparams, parameter_list);
1541*a67afe4dSAndroid Build Coastguard Worker break;
1542*a67afe4dSAndroid Build Coastguard Worker
1543*a67afe4dSAndroid Build Coastguard Worker case CHUNK(104,73,83,84): /* hIST */
1544*a67afe4dSAndroid Build Coastguard Worker if (nparams <= 256)
1545*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_hIST, nparams, parameter_list);
1546*a67afe4dSAndroid Build Coastguard Worker break;
1547*a67afe4dSAndroid Build Coastguard Worker
1548*a67afe4dSAndroid Build Coastguard Worker case CHUNK(115,66,73,84): /* sBIT */
1549*a67afe4dSAndroid Build Coastguard Worker if (nparams <= 4)
1550*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_sBIT, nparams, parameter_list);
1551*a67afe4dSAndroid Build Coastguard Worker break;
1552*a67afe4dSAndroid Build Coastguard Worker
1553*a67afe4dSAndroid Build Coastguard Worker #if 0
1554*a67afe4dSAndroid Build Coastguard Worker case CHUNK(115,80,76,84): /* sPLT */
1555*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_sPLT, nparams, parameter_list);
1556*a67afe4dSAndroid Build Coastguard Worker #endif
1557*a67afe4dSAndroid Build Coastguard Worker
1558*a67afe4dSAndroid Build Coastguard Worker default:
1559*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng --insert \"%s\": unrecognized chunk name\n",
1560*a67afe4dSAndroid Build Coastguard Worker what);
1561*a67afe4dSAndroid Build Coastguard Worker exit(1);
1562*a67afe4dSAndroid Build Coastguard Worker }
1563*a67afe4dSAndroid Build Coastguard Worker
1564*a67afe4dSAndroid Build Coastguard Worker bad_parameter_count(what, nparams);
1565*a67afe4dSAndroid Build Coastguard Worker return NULL;
1566*a67afe4dSAndroid Build Coastguard Worker }
1567*a67afe4dSAndroid Build Coastguard Worker
1568*a67afe4dSAndroid Build Coastguard Worker /* This is necessary because libpng expects writeable strings for things like
1569*a67afe4dSAndroid Build Coastguard Worker * text chunks (maybe this should be fixed...)
1570*a67afe4dSAndroid Build Coastguard Worker */
1571*a67afe4dSAndroid Build Coastguard Worker static png_charp
strstash(png_const_charp foo)1572*a67afe4dSAndroid Build Coastguard Worker strstash(png_const_charp foo)
1573*a67afe4dSAndroid Build Coastguard Worker {
1574*a67afe4dSAndroid Build Coastguard Worker /* The program indicates a memory allocation error by crashing, this is by
1575*a67afe4dSAndroid Build Coastguard Worker * design.
1576*a67afe4dSAndroid Build Coastguard Worker */
1577*a67afe4dSAndroid Build Coastguard Worker if (foo != NULL)
1578*a67afe4dSAndroid Build Coastguard Worker {
1579*a67afe4dSAndroid Build Coastguard Worker png_charp bar = malloc(strlen(foo)+1);
1580*a67afe4dSAndroid Build Coastguard Worker return strcpy(bar, foo);
1581*a67afe4dSAndroid Build Coastguard Worker }
1582*a67afe4dSAndroid Build Coastguard Worker
1583*a67afe4dSAndroid Build Coastguard Worker return NULL;
1584*a67afe4dSAndroid Build Coastguard Worker }
1585*a67afe4dSAndroid Build Coastguard Worker
1586*a67afe4dSAndroid Build Coastguard Worker static png_charp
strstash_list(const png_const_charp * text)1587*a67afe4dSAndroid Build Coastguard Worker strstash_list(const png_const_charp *text)
1588*a67afe4dSAndroid Build Coastguard Worker {
1589*a67afe4dSAndroid Build Coastguard Worker size_t foo = 0;
1590*a67afe4dSAndroid Build Coastguard Worker png_charp result, bar;
1591*a67afe4dSAndroid Build Coastguard Worker const png_const_charp *line = text;
1592*a67afe4dSAndroid Build Coastguard Worker
1593*a67afe4dSAndroid Build Coastguard Worker while (*line != NULL)
1594*a67afe4dSAndroid Build Coastguard Worker foo += strlen(*line++);
1595*a67afe4dSAndroid Build Coastguard Worker
1596*a67afe4dSAndroid Build Coastguard Worker result = bar = malloc(foo+1);
1597*a67afe4dSAndroid Build Coastguard Worker
1598*a67afe4dSAndroid Build Coastguard Worker line = text;
1599*a67afe4dSAndroid Build Coastguard Worker while (*line != NULL)
1600*a67afe4dSAndroid Build Coastguard Worker {
1601*a67afe4dSAndroid Build Coastguard Worker foo = strlen(*line);
1602*a67afe4dSAndroid Build Coastguard Worker memcpy(bar, *line++, foo);
1603*a67afe4dSAndroid Build Coastguard Worker bar += foo;
1604*a67afe4dSAndroid Build Coastguard Worker }
1605*a67afe4dSAndroid Build Coastguard Worker
1606*a67afe4dSAndroid Build Coastguard Worker *bar = 0;
1607*a67afe4dSAndroid Build Coastguard Worker return result;
1608*a67afe4dSAndroid Build Coastguard Worker }
1609*a67afe4dSAndroid Build Coastguard Worker
1610*a67afe4dSAndroid Build Coastguard Worker /* These are used to insert Copyright and Licence fields, they allow the text to
1611*a67afe4dSAndroid Build Coastguard Worker * have \n unlike the --insert option.
1612*a67afe4dSAndroid Build Coastguard Worker */
1613*a67afe4dSAndroid Build Coastguard Worker static chunk_insert *
add_tEXt(const char * key,const png_const_charp * text)1614*a67afe4dSAndroid Build Coastguard Worker add_tEXt(const char *key, const png_const_charp *text)
1615*a67afe4dSAndroid Build Coastguard Worker {
1616*a67afe4dSAndroid Build Coastguard Worker static char what[5] = { 116, 69, 88, 116, 0 };
1617*a67afe4dSAndroid Build Coastguard Worker png_charp parameter_list[3];
1618*a67afe4dSAndroid Build Coastguard Worker
1619*a67afe4dSAndroid Build Coastguard Worker parameter_list[0] = strstash(key);
1620*a67afe4dSAndroid Build Coastguard Worker parameter_list[1] = strstash_list(text);
1621*a67afe4dSAndroid Build Coastguard Worker parameter_list[2] = NULL;
1622*a67afe4dSAndroid Build Coastguard Worker
1623*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_tEXt, 2, parameter_list);
1624*a67afe4dSAndroid Build Coastguard Worker }
1625*a67afe4dSAndroid Build Coastguard Worker
1626*a67afe4dSAndroid Build Coastguard Worker static chunk_insert *
add_iTXt(const char * key,const char * language,const char * language_key,const png_const_charp * text)1627*a67afe4dSAndroid Build Coastguard Worker add_iTXt(const char *key, const char *language, const char *language_key,
1628*a67afe4dSAndroid Build Coastguard Worker const png_const_charp *text)
1629*a67afe4dSAndroid Build Coastguard Worker {
1630*a67afe4dSAndroid Build Coastguard Worker static char what[5] = { 105, 84, 88, 116, 0 };
1631*a67afe4dSAndroid Build Coastguard Worker png_charp parameter_list[5];
1632*a67afe4dSAndroid Build Coastguard Worker
1633*a67afe4dSAndroid Build Coastguard Worker parameter_list[0] = strstash(key);
1634*a67afe4dSAndroid Build Coastguard Worker parameter_list[1] = strstash(language);
1635*a67afe4dSAndroid Build Coastguard Worker parameter_list[2] = strstash(language_key);
1636*a67afe4dSAndroid Build Coastguard Worker parameter_list[3] = strstash_list(text);
1637*a67afe4dSAndroid Build Coastguard Worker parameter_list[4] = NULL;
1638*a67afe4dSAndroid Build Coastguard Worker
1639*a67afe4dSAndroid Build Coastguard Worker return make_insert(what, insert_iTXt, 4, parameter_list);
1640*a67afe4dSAndroid Build Coastguard Worker }
1641*a67afe4dSAndroid Build Coastguard Worker
1642*a67afe4dSAndroid Build Coastguard Worker /* This is a not-very-good parser for a sequence of numbers (including 0). It
1643*a67afe4dSAndroid Build Coastguard Worker * doesn't accept some apparently valid things, but it accepts all the sensible
1644*a67afe4dSAndroid Build Coastguard Worker * combinations.
1645*a67afe4dSAndroid Build Coastguard Worker */
1646*a67afe4dSAndroid Build Coastguard Worker static void
parse_color(char * arg,unsigned int * colors)1647*a67afe4dSAndroid Build Coastguard Worker parse_color(char *arg, unsigned int *colors)
1648*a67afe4dSAndroid Build Coastguard Worker {
1649*a67afe4dSAndroid Build Coastguard Worker unsigned int ncolors = 0;
1650*a67afe4dSAndroid Build Coastguard Worker
1651*a67afe4dSAndroid Build Coastguard Worker while (*arg && ncolors < 4)
1652*a67afe4dSAndroid Build Coastguard Worker {
1653*a67afe4dSAndroid Build Coastguard Worker char *ep = arg;
1654*a67afe4dSAndroid Build Coastguard Worker
1655*a67afe4dSAndroid Build Coastguard Worker unsigned long ul = strtoul(arg, &ep, 0);
1656*a67afe4dSAndroid Build Coastguard Worker
1657*a67afe4dSAndroid Build Coastguard Worker if (ul > 65535)
1658*a67afe4dSAndroid Build Coastguard Worker {
1659*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng --color=...'%s': too big\n", arg);
1660*a67afe4dSAndroid Build Coastguard Worker exit(1);
1661*a67afe4dSAndroid Build Coastguard Worker }
1662*a67afe4dSAndroid Build Coastguard Worker
1663*a67afe4dSAndroid Build Coastguard Worker if (ep == arg)
1664*a67afe4dSAndroid Build Coastguard Worker {
1665*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg);
1666*a67afe4dSAndroid Build Coastguard Worker exit(1);
1667*a67afe4dSAndroid Build Coastguard Worker }
1668*a67afe4dSAndroid Build Coastguard Worker
1669*a67afe4dSAndroid Build Coastguard Worker if (*ep) ++ep; /* skip a separator */
1670*a67afe4dSAndroid Build Coastguard Worker arg = ep;
1671*a67afe4dSAndroid Build Coastguard Worker
1672*a67afe4dSAndroid Build Coastguard Worker colors[++ncolors] = (unsigned int)ul; /* checked above */
1673*a67afe4dSAndroid Build Coastguard Worker }
1674*a67afe4dSAndroid Build Coastguard Worker
1675*a67afe4dSAndroid Build Coastguard Worker if (*arg)
1676*a67afe4dSAndroid Build Coastguard Worker {
1677*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng --color=...'%s': too many values\n", arg);
1678*a67afe4dSAndroid Build Coastguard Worker exit(1);
1679*a67afe4dSAndroid Build Coastguard Worker }
1680*a67afe4dSAndroid Build Coastguard Worker
1681*a67afe4dSAndroid Build Coastguard Worker *colors = ncolors;
1682*a67afe4dSAndroid Build Coastguard Worker }
1683*a67afe4dSAndroid Build Coastguard Worker
1684*a67afe4dSAndroid Build Coastguard Worker int
main(int argc,char ** argv)1685*a67afe4dSAndroid Build Coastguard Worker main(int argc, char **argv)
1686*a67afe4dSAndroid Build Coastguard Worker {
1687*a67afe4dSAndroid Build Coastguard Worker FILE *fp = stdout;
1688*a67afe4dSAndroid Build Coastguard Worker const char *file_name = NULL;
1689*a67afe4dSAndroid Build Coastguard Worker int color_type = 8; /* invalid */
1690*a67afe4dSAndroid Build Coastguard Worker int bit_depth = 32; /* invalid */
1691*a67afe4dSAndroid Build Coastguard Worker int small = 0; /* make full size images */
1692*a67afe4dSAndroid Build Coastguard Worker int tRNS = 0; /* don't output a tRNS chunk */
1693*a67afe4dSAndroid Build Coastguard Worker unsigned int colors[5];
1694*a67afe4dSAndroid Build Coastguard Worker unsigned int filters = PNG_ALL_FILTERS;
1695*a67afe4dSAndroid Build Coastguard Worker png_fixed_point gamma = 0; /* not set */
1696*a67afe4dSAndroid Build Coastguard Worker chunk_insert *head_insert = NULL;
1697*a67afe4dSAndroid Build Coastguard Worker chunk_insert **insert_ptr = &head_insert;
1698*a67afe4dSAndroid Build Coastguard Worker
1699*a67afe4dSAndroid Build Coastguard Worker memset(colors, 0, sizeof colors);
1700*a67afe4dSAndroid Build Coastguard Worker
1701*a67afe4dSAndroid Build Coastguard Worker while (--argc > 0)
1702*a67afe4dSAndroid Build Coastguard Worker {
1703*a67afe4dSAndroid Build Coastguard Worker char *arg = *++argv;
1704*a67afe4dSAndroid Build Coastguard Worker
1705*a67afe4dSAndroid Build Coastguard Worker if (strcmp(arg, "--small") == 0)
1706*a67afe4dSAndroid Build Coastguard Worker {
1707*a67afe4dSAndroid Build Coastguard Worker small = 1;
1708*a67afe4dSAndroid Build Coastguard Worker continue;
1709*a67afe4dSAndroid Build Coastguard Worker }
1710*a67afe4dSAndroid Build Coastguard Worker
1711*a67afe4dSAndroid Build Coastguard Worker if (strcmp(arg, "--tRNS") == 0)
1712*a67afe4dSAndroid Build Coastguard Worker {
1713*a67afe4dSAndroid Build Coastguard Worker tRNS = 1;
1714*a67afe4dSAndroid Build Coastguard Worker continue;
1715*a67afe4dSAndroid Build Coastguard Worker }
1716*a67afe4dSAndroid Build Coastguard Worker
1717*a67afe4dSAndroid Build Coastguard Worker if (strcmp(arg, "--sRGB") == 0)
1718*a67afe4dSAndroid Build Coastguard Worker {
1719*a67afe4dSAndroid Build Coastguard Worker gamma = PNG_DEFAULT_sRGB;
1720*a67afe4dSAndroid Build Coastguard Worker continue;
1721*a67afe4dSAndroid Build Coastguard Worker }
1722*a67afe4dSAndroid Build Coastguard Worker
1723*a67afe4dSAndroid Build Coastguard Worker if (strcmp(arg, "--linear") == 0)
1724*a67afe4dSAndroid Build Coastguard Worker {
1725*a67afe4dSAndroid Build Coastguard Worker gamma = PNG_FP_1;
1726*a67afe4dSAndroid Build Coastguard Worker continue;
1727*a67afe4dSAndroid Build Coastguard Worker }
1728*a67afe4dSAndroid Build Coastguard Worker
1729*a67afe4dSAndroid Build Coastguard Worker if (strcmp(arg, "--1.8") == 0)
1730*a67afe4dSAndroid Build Coastguard Worker {
1731*a67afe4dSAndroid Build Coastguard Worker gamma = PNG_GAMMA_MAC_18;
1732*a67afe4dSAndroid Build Coastguard Worker continue;
1733*a67afe4dSAndroid Build Coastguard Worker }
1734*a67afe4dSAndroid Build Coastguard Worker
1735*a67afe4dSAndroid Build Coastguard Worker if (strcmp(arg, "--nofilters") == 0)
1736*a67afe4dSAndroid Build Coastguard Worker {
1737*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_NONE;
1738*a67afe4dSAndroid Build Coastguard Worker continue;
1739*a67afe4dSAndroid Build Coastguard Worker }
1740*a67afe4dSAndroid Build Coastguard Worker
1741*a67afe4dSAndroid Build Coastguard Worker if (strncmp(arg, "--color=", 8) == 0)
1742*a67afe4dSAndroid Build Coastguard Worker {
1743*a67afe4dSAndroid Build Coastguard Worker parse_color(arg+8, colors);
1744*a67afe4dSAndroid Build Coastguard Worker continue;
1745*a67afe4dSAndroid Build Coastguard Worker }
1746*a67afe4dSAndroid Build Coastguard Worker
1747*a67afe4dSAndroid Build Coastguard Worker if (argc >= 3 && strcmp(arg, "--insert") == 0)
1748*a67afe4dSAndroid Build Coastguard Worker {
1749*a67afe4dSAndroid Build Coastguard Worker png_const_charp what = *++argv;
1750*a67afe4dSAndroid Build Coastguard Worker png_charp param = *++argv;
1751*a67afe4dSAndroid Build Coastguard Worker chunk_insert *new_insert;
1752*a67afe4dSAndroid Build Coastguard Worker
1753*a67afe4dSAndroid Build Coastguard Worker argc -= 2;
1754*a67afe4dSAndroid Build Coastguard Worker
1755*a67afe4dSAndroid Build Coastguard Worker new_insert = find_insert(what, param);
1756*a67afe4dSAndroid Build Coastguard Worker
1757*a67afe4dSAndroid Build Coastguard Worker if (new_insert != NULL)
1758*a67afe4dSAndroid Build Coastguard Worker {
1759*a67afe4dSAndroid Build Coastguard Worker *insert_ptr = new_insert;
1760*a67afe4dSAndroid Build Coastguard Worker insert_ptr = &new_insert->next;
1761*a67afe4dSAndroid Build Coastguard Worker }
1762*a67afe4dSAndroid Build Coastguard Worker
1763*a67afe4dSAndroid Build Coastguard Worker continue;
1764*a67afe4dSAndroid Build Coastguard Worker }
1765*a67afe4dSAndroid Build Coastguard Worker
1766*a67afe4dSAndroid Build Coastguard Worker if (arg[0] == '-')
1767*a67afe4dSAndroid Build Coastguard Worker {
1768*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: %s: invalid option\n", arg);
1769*a67afe4dSAndroid Build Coastguard Worker exit(1);
1770*a67afe4dSAndroid Build Coastguard Worker }
1771*a67afe4dSAndroid Build Coastguard Worker
1772*a67afe4dSAndroid Build Coastguard Worker if (strcmp(arg, "palette") == 0)
1773*a67afe4dSAndroid Build Coastguard Worker {
1774*a67afe4dSAndroid Build Coastguard Worker color_type = PNG_COLOR_TYPE_PALETTE;
1775*a67afe4dSAndroid Build Coastguard Worker continue;
1776*a67afe4dSAndroid Build Coastguard Worker }
1777*a67afe4dSAndroid Build Coastguard Worker
1778*a67afe4dSAndroid Build Coastguard Worker if (strncmp(arg, "gray", 4) == 0)
1779*a67afe4dSAndroid Build Coastguard Worker {
1780*a67afe4dSAndroid Build Coastguard Worker if (arg[4] == 0)
1781*a67afe4dSAndroid Build Coastguard Worker {
1782*a67afe4dSAndroid Build Coastguard Worker color_type = PNG_COLOR_TYPE_GRAY;
1783*a67afe4dSAndroid Build Coastguard Worker continue;
1784*a67afe4dSAndroid Build Coastguard Worker }
1785*a67afe4dSAndroid Build Coastguard Worker
1786*a67afe4dSAndroid Build Coastguard Worker else if (strcmp(arg+4, "a") == 0 ||
1787*a67afe4dSAndroid Build Coastguard Worker strcmp(arg+4, "alpha") == 0 ||
1788*a67afe4dSAndroid Build Coastguard Worker strcmp(arg+4, "-alpha") == 0)
1789*a67afe4dSAndroid Build Coastguard Worker {
1790*a67afe4dSAndroid Build Coastguard Worker color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
1791*a67afe4dSAndroid Build Coastguard Worker continue;
1792*a67afe4dSAndroid Build Coastguard Worker }
1793*a67afe4dSAndroid Build Coastguard Worker }
1794*a67afe4dSAndroid Build Coastguard Worker
1795*a67afe4dSAndroid Build Coastguard Worker if (strncmp(arg, "rgb", 3) == 0)
1796*a67afe4dSAndroid Build Coastguard Worker {
1797*a67afe4dSAndroid Build Coastguard Worker if (arg[3] == 0)
1798*a67afe4dSAndroid Build Coastguard Worker {
1799*a67afe4dSAndroid Build Coastguard Worker color_type = PNG_COLOR_TYPE_RGB;
1800*a67afe4dSAndroid Build Coastguard Worker continue;
1801*a67afe4dSAndroid Build Coastguard Worker }
1802*a67afe4dSAndroid Build Coastguard Worker
1803*a67afe4dSAndroid Build Coastguard Worker else if (strcmp(arg+3, "a") == 0 ||
1804*a67afe4dSAndroid Build Coastguard Worker strcmp(arg+3, "alpha") == 0 ||
1805*a67afe4dSAndroid Build Coastguard Worker strcmp(arg+3, "-alpha") == 0)
1806*a67afe4dSAndroid Build Coastguard Worker {
1807*a67afe4dSAndroid Build Coastguard Worker color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1808*a67afe4dSAndroid Build Coastguard Worker continue;
1809*a67afe4dSAndroid Build Coastguard Worker }
1810*a67afe4dSAndroid Build Coastguard Worker }
1811*a67afe4dSAndroid Build Coastguard Worker
1812*a67afe4dSAndroid Build Coastguard Worker if (color_type == 8 && isdigit(arg[0]))
1813*a67afe4dSAndroid Build Coastguard Worker {
1814*a67afe4dSAndroid Build Coastguard Worker color_type = atoi(arg);
1815*a67afe4dSAndroid Build Coastguard Worker if (color_type < 0 || color_type > 6 || color_type == 1 ||
1816*a67afe4dSAndroid Build Coastguard Worker color_type == 5)
1817*a67afe4dSAndroid Build Coastguard Worker {
1818*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: %s: not a valid color type\n", arg);
1819*a67afe4dSAndroid Build Coastguard Worker exit(1);
1820*a67afe4dSAndroid Build Coastguard Worker }
1821*a67afe4dSAndroid Build Coastguard Worker
1822*a67afe4dSAndroid Build Coastguard Worker continue;
1823*a67afe4dSAndroid Build Coastguard Worker }
1824*a67afe4dSAndroid Build Coastguard Worker
1825*a67afe4dSAndroid Build Coastguard Worker if (bit_depth == 32 && isdigit(arg[0]))
1826*a67afe4dSAndroid Build Coastguard Worker {
1827*a67afe4dSAndroid Build Coastguard Worker bit_depth = atoi(arg);
1828*a67afe4dSAndroid Build Coastguard Worker if (bit_depth <= 0 || bit_depth > 16 ||
1829*a67afe4dSAndroid Build Coastguard Worker (bit_depth & -bit_depth) != bit_depth)
1830*a67afe4dSAndroid Build Coastguard Worker {
1831*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: %s: not a valid bit depth\n", arg);
1832*a67afe4dSAndroid Build Coastguard Worker exit(1);
1833*a67afe4dSAndroid Build Coastguard Worker }
1834*a67afe4dSAndroid Build Coastguard Worker
1835*a67afe4dSAndroid Build Coastguard Worker continue;
1836*a67afe4dSAndroid Build Coastguard Worker }
1837*a67afe4dSAndroid Build Coastguard Worker
1838*a67afe4dSAndroid Build Coastguard Worker if (argc == 1) /* It's the file name */
1839*a67afe4dSAndroid Build Coastguard Worker {
1840*a67afe4dSAndroid Build Coastguard Worker fp = fopen(arg, "wb");
1841*a67afe4dSAndroid Build Coastguard Worker if (fp == NULL)
1842*a67afe4dSAndroid Build Coastguard Worker {
1843*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "%s: %s: could not open\n", arg, strerror(errno));
1844*a67afe4dSAndroid Build Coastguard Worker exit(1);
1845*a67afe4dSAndroid Build Coastguard Worker }
1846*a67afe4dSAndroid Build Coastguard Worker
1847*a67afe4dSAndroid Build Coastguard Worker file_name = arg;
1848*a67afe4dSAndroid Build Coastguard Worker continue;
1849*a67afe4dSAndroid Build Coastguard Worker }
1850*a67afe4dSAndroid Build Coastguard Worker
1851*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: %s: unknown argument\n", arg);
1852*a67afe4dSAndroid Build Coastguard Worker exit(1);
1853*a67afe4dSAndroid Build Coastguard Worker } /* argument while loop */
1854*a67afe4dSAndroid Build Coastguard Worker
1855*a67afe4dSAndroid Build Coastguard Worker if (color_type == 8 || bit_depth == 32)
1856*a67afe4dSAndroid Build Coastguard Worker {
1857*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "usage: makepng [--small] [--sRGB|--linear|--1.8] "
1858*a67afe4dSAndroid Build Coastguard Worker "[--color=...] color-type bit-depth [file-name]\n"
1859*a67afe4dSAndroid Build Coastguard Worker " Make a test PNG file, by default writes to stdout.\n"
1860*a67afe4dSAndroid Build Coastguard Worker " Other options are available, UTSL.\n");
1861*a67afe4dSAndroid Build Coastguard Worker exit(1);
1862*a67afe4dSAndroid Build Coastguard Worker }
1863*a67afe4dSAndroid Build Coastguard Worker
1864*a67afe4dSAndroid Build Coastguard Worker /* Check the colors */
1865*a67afe4dSAndroid Build Coastguard Worker {
1866*a67afe4dSAndroid Build Coastguard Worker unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U :
1867*a67afe4dSAndroid Build Coastguard Worker (1U<<bit_depth)-1);
1868*a67afe4dSAndroid Build Coastguard Worker unsigned int i;
1869*a67afe4dSAndroid Build Coastguard Worker
1870*a67afe4dSAndroid Build Coastguard Worker for (i=1; i<=colors[0]; ++i)
1871*a67afe4dSAndroid Build Coastguard Worker if (colors[i] > lim)
1872*a67afe4dSAndroid Build Coastguard Worker {
1873*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n",
1874*a67afe4dSAndroid Build Coastguard Worker colors[i], lim);
1875*a67afe4dSAndroid Build Coastguard Worker exit(1);
1876*a67afe4dSAndroid Build Coastguard Worker }
1877*a67afe4dSAndroid Build Coastguard Worker }
1878*a67afe4dSAndroid Build Coastguard Worker
1879*a67afe4dSAndroid Build Coastguard Worker /* small and colors are incompatible (will probably crash if both are used at
1880*a67afe4dSAndroid Build Coastguard Worker * the same time!)
1881*a67afe4dSAndroid Build Coastguard Worker */
1882*a67afe4dSAndroid Build Coastguard Worker if (small && colors[0] != 0)
1883*a67afe4dSAndroid Build Coastguard Worker {
1884*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "makepng: --color --small: only one at a time!\n");
1885*a67afe4dSAndroid Build Coastguard Worker exit(1);
1886*a67afe4dSAndroid Build Coastguard Worker }
1887*a67afe4dSAndroid Build Coastguard Worker
1888*a67afe4dSAndroid Build Coastguard Worker /* Restrict the filters for more speed to those we know are used for the
1889*a67afe4dSAndroid Build Coastguard Worker * generated images.
1890*a67afe4dSAndroid Build Coastguard Worker */
1891*a67afe4dSAndroid Build Coastguard Worker if (filters == PNG_ALL_FILTERS && !small/*small provides defaults*/)
1892*a67afe4dSAndroid Build Coastguard Worker {
1893*a67afe4dSAndroid Build Coastguard Worker if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8)
1894*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_NONE;
1895*a67afe4dSAndroid Build Coastguard Worker
1896*a67afe4dSAndroid Build Coastguard Worker else if (color_type & PNG_COLOR_MASK_COLOR) /* rgb */
1897*a67afe4dSAndroid Build Coastguard Worker {
1898*a67afe4dSAndroid Build Coastguard Worker if (bit_depth == 8)
1899*a67afe4dSAndroid Build Coastguard Worker filters &= ~(PNG_FILTER_NONE | PNG_FILTER_AVG);
1900*a67afe4dSAndroid Build Coastguard Worker
1901*a67afe4dSAndroid Build Coastguard Worker else
1902*a67afe4dSAndroid Build Coastguard Worker filters = PNG_FILTER_SUB | PNG_FILTER_PAETH;
1903*a67afe4dSAndroid Build Coastguard Worker }
1904*a67afe4dSAndroid Build Coastguard Worker
1905*a67afe4dSAndroid Build Coastguard Worker else /* gray 8 or 16-bit */
1906*a67afe4dSAndroid Build Coastguard Worker filters &= ~PNG_FILTER_NONE;
1907*a67afe4dSAndroid Build Coastguard Worker }
1908*a67afe4dSAndroid Build Coastguard Worker
1909*a67afe4dSAndroid Build Coastguard Worker /* Insert standard copyright and licence text. */
1910*a67afe4dSAndroid Build Coastguard Worker {
1911*a67afe4dSAndroid Build Coastguard Worker static png_const_charp copyright[] =
1912*a67afe4dSAndroid Build Coastguard Worker {
1913*a67afe4dSAndroid Build Coastguard Worker COPYRIGHT, /* ISO-Latin-1 */
1914*a67afe4dSAndroid Build Coastguard Worker NULL
1915*a67afe4dSAndroid Build Coastguard Worker };
1916*a67afe4dSAndroid Build Coastguard Worker static png_const_charp licensing[] =
1917*a67afe4dSAndroid Build Coastguard Worker {
1918*a67afe4dSAndroid Build Coastguard Worker IMAGE_LICENSING, /* UTF-8 */
1919*a67afe4dSAndroid Build Coastguard Worker NULL
1920*a67afe4dSAndroid Build Coastguard Worker };
1921*a67afe4dSAndroid Build Coastguard Worker
1922*a67afe4dSAndroid Build Coastguard Worker chunk_insert *new_insert;
1923*a67afe4dSAndroid Build Coastguard Worker
1924*a67afe4dSAndroid Build Coastguard Worker new_insert = add_tEXt("Copyright", copyright);
1925*a67afe4dSAndroid Build Coastguard Worker if (new_insert != NULL)
1926*a67afe4dSAndroid Build Coastguard Worker {
1927*a67afe4dSAndroid Build Coastguard Worker *insert_ptr = new_insert;
1928*a67afe4dSAndroid Build Coastguard Worker insert_ptr = &new_insert->next;
1929*a67afe4dSAndroid Build Coastguard Worker }
1930*a67afe4dSAndroid Build Coastguard Worker
1931*a67afe4dSAndroid Build Coastguard Worker new_insert = add_iTXt("Licensing", "en", NULL, licensing);
1932*a67afe4dSAndroid Build Coastguard Worker if (new_insert != NULL)
1933*a67afe4dSAndroid Build Coastguard Worker {
1934*a67afe4dSAndroid Build Coastguard Worker *insert_ptr = new_insert;
1935*a67afe4dSAndroid Build Coastguard Worker insert_ptr = &new_insert->next;
1936*a67afe4dSAndroid Build Coastguard Worker }
1937*a67afe4dSAndroid Build Coastguard Worker }
1938*a67afe4dSAndroid Build Coastguard Worker
1939*a67afe4dSAndroid Build Coastguard Worker {
1940*a67afe4dSAndroid Build Coastguard Worker int ret = write_png(&file_name, fp, color_type, bit_depth, gamma,
1941*a67afe4dSAndroid Build Coastguard Worker head_insert, filters, colors, small, tRNS);
1942*a67afe4dSAndroid Build Coastguard Worker
1943*a67afe4dSAndroid Build Coastguard Worker if (ret != 0 && file_name != NULL)
1944*a67afe4dSAndroid Build Coastguard Worker remove(file_name);
1945*a67afe4dSAndroid Build Coastguard Worker
1946*a67afe4dSAndroid Build Coastguard Worker return ret;
1947*a67afe4dSAndroid Build Coastguard Worker }
1948*a67afe4dSAndroid Build Coastguard Worker }
1949