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