Home | History | Annotate | Download | only in libtests
      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
    155 flooru(double d)
    156 {
    157    d = floor(d);
    158    return (unsigned int)d;
    159 }
    160 
    161 static png_byte
    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
    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
    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
    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
    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
    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
    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 */
    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
    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
    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 */
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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 *
   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 *
   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
   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
   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 *
   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 *
   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
   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
   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