[libpng16] Added the ability for contrib/libtests/makepng.c to make a PNG with just one

color. This is useful for debugging pngstest color inaccuracy reports.
This commit is contained in:
John Bowler 2012-11-13 19:18:53 -06:00 committed by Glenn Randers-Pehrson
parent 4314d63792
commit f2aacefb3f
3 changed files with 263 additions and 56 deletions

View File

@ -1,5 +1,5 @@
Libpng 1.6.0beta32 - November 2, 2012 Libpng 1.6.0beta32 - November 14, 2012
This is not intended to be a public release. It will be replaced This is not intended to be a public release. It will be replaced
within a few weeks by a public version or by another test version. within a few weeks by a public version or by another test version.
@ -545,8 +545,10 @@ Version 1.6.0beta31 [November 1, 2012]
gain; implementing full ICC color correction may be desireable but is left gain; implementing full ICC color correction may be desireable but is left
up to applications. up to applications.
Version 1.6.0beta32 [November 2, 2012] Version 1.6.0beta32 [November 14, 2012]
Fixed an intermittent SEGV in pngstest. Fixed an intermittent SEGV in pngstest due to an uninitialized array element.
Added the ability for contrib/libtests/makepng.c to make a PNG with just one
color. This is useful for debugging pngstest color inaccuracy reports.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit (subscription required; visit

View File

@ -4297,8 +4297,10 @@ Version 1.6.0beta31 [November 1, 2012]
gain; implementing full ICC color correction may be desireable but is left gain; implementing full ICC color correction may be desireable but is left
up to applications. up to applications.
Version 1.6.0beta32 [November 2, 2012] Version 1.6.0beta32 [November 14, 2012]
Fixed an intermittent SEGV in pngstest. Fixed an intermittent SEGV in pngstest due to an uninitialized array element.
Added the ability for contrib/libtests/makepng.c to make a PNG with just one
color. This is useful for debugging pngstest color inaccuracy reports.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit (subscription required; visit

View File

@ -10,7 +10,8 @@
* *
* Make a test PNG image. The arguments are as follows: * Make a test PNG image. The arguments are as follows:
* *
* makepng [--sRGB|--linear|--1.8] color-type bit-depth [file-name] * makepng [--sRGB|--linear|--1.8] [--color=<color>] color-type bit-depth \
* [file-name]
* *
* The color-type may be numeric (and must match the numbers used by the PNG * The color-type may be numeric (and must match the numbers used by the PNG
* specification) or one of the format names listed below. The bit-depth is the * specification) or one of the format names listed below. The bit-depth is the
@ -23,7 +24,8 @@
* approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909 * approximately value^(1/1.45) to the color values and so a gAMA chunk of 65909
* is written (1.45/2.2). * is written (1.45/2.2).
* *
* The image data is generated internally. The images used are as follows: * The image data is generated internally. Unless --color is given the images
* used are as follows:
* *
* 1 channel: a square image with a diamond, the least luminous colors are on * 1 channel: a square image with a diamond, the least luminous colors are on
* the edge of the image, the most luminous in the center. * the edge of the image, the most luminous in the center.
@ -61,6 +63,11 @@
* Row filtering is turned off (the 'none' filter is used on every row) and the * Row filtering is turned off (the 'none' filter is used on every row) and the
* images are not interlaced. * images are not interlaced.
* *
* If --color is given then the whole image has that color, color-mapped images
* will have exactly one palette entry and all image files with be 16x16 in
* size. The color value is 1 to 4 decimal numbers as appropriate for the color
* type.
*
* If file-name is given then the PNG is written to that file, else it is * If file-name is given then the PNG is written to that file, else it is
* written to stdout. Notice that stdout is not supported on systems where, by * written to stdout. Notice that stdout is not supported on systems where, by
* default, it assumes text output; this program makes no attempt to change the * default, it assumes text output; this program makes no attempt to change the
@ -128,7 +135,12 @@ pixel_depth_of_type(int color_type, int bit_depth)
} }
static unsigned int static unsigned int
image_size_of_type(int color_type, int bit_depth) image_size_of_type(int color_type, int bit_depth, unsigned int *colors)
{
if (*colors)
return 16;
else
{ {
int pixel_depth = pixel_depth_of_type(color_type, bit_depth); int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
@ -141,6 +153,7 @@ image_size_of_type(int color_type, int bit_depth)
else else
return 256; return 256;
} }
}
static void static void
set_color(png_colorp color, png_bytep trans, unsigned int red, set_color(png_colorp color, png_bytep trans, unsigned int red,
@ -155,7 +168,7 @@ set_color(png_colorp color, png_bytep trans, unsigned int red,
static int static int
generate_palette(png_colorp palette, png_bytep trans, int bit_depth, generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
png_const_bytep gamma_table) png_const_bytep gamma_table, unsigned int *colors)
{ {
/* /*
* 1-bit: entry 0 is transparent-red, entry 1 is opaque-white * 1-bit: entry 0 is transparent-red, entry 1 is opaque-white
@ -166,6 +179,34 @@ generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
* 4-bit: the 16 combinations of the 2-bit case * 4-bit: the 16 combinations of the 2-bit case
* 8-bit: the 256 combinations of the 4-bit case * 8-bit: the 256 combinations of the 4-bit case
*/ */
switch (colors[0])
{
default:
fprintf(stderr, "makepng: --colors=...: invalid count %u\n",
colors[0]);
exit(1);
case 1:
set_color(palette+0, trans+0, colors[1], colors[1], colors[1], 255,
gamma_table);
return 1;
case 2:
set_color(palette+0, trans+0, colors[1], colors[1], colors[1],
colors[2], gamma_table);
return 1;
case 3:
set_color(palette+0, trans+0, colors[1], colors[2], colors[3], 255,
gamma_table);
return 1;
case 4:
set_color(palette+0, trans+0, colors[1], colors[2], colors[3],
colors[4], gamma_table);
return 1;
case 0:
if (bit_depth == 1) if (bit_depth == 1)
{ {
set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table); set_color(palette+0, trans+0, 255, 0, 0, 0, gamma_table);
@ -182,7 +223,8 @@ generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
{ {
ip = x + (size * y); ip = x + (size * y);
/* size is at most 16, so the scaled value below fits in 16 bits */ /* size is at most 16, so the scaled value below fits in 16 bits
*/
# define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2)) # define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2))
# define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\ # define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\
(interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\ (interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\
@ -201,6 +243,7 @@ generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
return ip+1; return ip+1;
} }
} }
}
static void static void
set_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth, set_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth,
@ -265,12 +308,13 @@ set_value(png_bytep row, size_t rowbytes, png_uint_32 x, unsigned int bit_depth,
static void static void
generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type, generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
int bit_depth, png_const_bytep gamma_table, double conv) int bit_depth, png_const_bytep gamma_table, double conv,
unsigned int *colors)
{ {
png_uint_32 size_max = image_size_of_type(color_type, bit_depth)-1; png_uint_32 size_max = image_size_of_type(color_type, bit_depth, colors)-1;
png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */ png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */
switch (channels_of_type(color_type)) if (colors[0] == 0) switch (channels_of_type(color_type))
{ {
/* 1 channel: a square image with a diamond, the least luminous colors are on /* 1 channel: a square image with a diamond, the least luminous colors are on
* the edge of the image, the most luminous in the center. * the edge of the image, the most luminous in the center.
@ -390,6 +434,98 @@ generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
fprintf(stderr, "makepng: internal bad channel count\n"); fprintf(stderr, "makepng: internal bad channel count\n");
exit(2); exit(2);
} }
else if (color_type & PNG_COLOR_MASK_PALETTE)
{
/* Palette with fixed color: the image rows are all 0 and the image width
* is 16.
*/
memset(row, rowbytes, 0);
}
else if (colors[0] == channels_of_type(color_type))
switch (channels_of_type(color_type))
{
case 1:
{
const png_uint_32 luma = colors[1];
png_uint_32 x;
for (x=0; x<=size_max; ++x)
set_value(row, rowbytes, x, bit_depth, luma, gamma_table,
conv);
}
break;
case 2:
{
const png_uint_32 luma = colors[1];
const png_uint_32 alpha = colors[2];
png_uint_32 x;
for (x=0; x<size_max; ++x)
{
set_value(row, rowbytes, 2*x, bit_depth, luma, gamma_table,
conv);
set_value(row, rowbytes, 2*x+1, bit_depth, alpha, gamma_table,
conv);
}
}
break;
case 3:
{
const png_uint_32 red = colors[1];
const png_uint_32 green = colors[2];
const png_uint_32 blue = colors[3];
png_uint_32 x;
for (x=0; x<=size_max; ++x)
{
set_value(row, rowbytes, 3*x+0, bit_depth, red, gamma_table,
conv);
set_value(row, rowbytes, 3*x+1, bit_depth, green, gamma_table,
conv);
set_value(row, rowbytes, 3*x+2, bit_depth, blue, gamma_table,
conv);
}
}
break;
case 4:
{
const png_uint_32 red = colors[1];
const png_uint_32 green = colors[2];
const png_uint_32 blue = colors[3];
const png_uint_32 alpha = colors[4];
png_uint_32 x;
for (x=0; x<=size_max; ++x)
{
set_value(row, rowbytes, 4*x+0, bit_depth, red, gamma_table,
conv);
set_value(row, rowbytes, 4*x+1, bit_depth, green, gamma_table,
conv);
set_value(row, rowbytes, 4*x+2, bit_depth, blue, gamma_table,
conv);
set_value(row, rowbytes, 4*x+3, bit_depth, alpha, gamma_table,
conv);
}
}
break;
default:
fprintf(stderr, "makepng: internal bad channel count\n");
exit(2);
}
else
{
fprintf(stderr,
"makepng: --color: count(%u) does not match channels(%u)\n",
colors[0], channels_of_type(color_type));
exit(1);
}
} }
@ -418,7 +554,7 @@ makepng_error(png_structp png_ptr, png_const_charp message)
static int /* 0 on success, else an error code */ static int /* 0 on success, else an error code */
write_png(const char **name, FILE *fp, int color_type, int bit_depth, write_png(const char **name, FILE *fp, int color_type, int bit_depth,
volatile png_fixed_point gamma, chunk_insert * volatile insert, volatile png_fixed_point gamma, chunk_insert * volatile insert,
unsigned int filters) unsigned int filters, unsigned int *colors)
{ {
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
name, makepng_error, makepng_warning); name, makepng_error, makepng_warning);
@ -452,7 +588,7 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
png_error(png_ptr, "OOM allocating info structure"); png_error(png_ptr, "OOM allocating info structure");
{ {
unsigned int size = image_size_of_type(color_type, bit_depth); unsigned int size = image_size_of_type(color_type, bit_depth, colors);
png_fixed_point real_gamma = 45455; /* For sRGB */ png_fixed_point real_gamma = 45455; /* For sRGB */
png_byte gamma_table[256]; png_byte gamma_table[256];
double conv; double conv;
@ -504,7 +640,8 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
png_color palette[256]; png_color palette[256];
png_byte trans[256]; png_byte trans[256];
npalette = generate_palette(palette, trans, bit_depth, gamma_table); npalette = generate_palette(palette, trans, bit_depth, gamma_table,
colors);
png_set_PLTE(png_ptr, info_ptr, palette, npalette); png_set_PLTE(png_ptr, info_ptr, palette, npalette);
png_set_tRNS(png_ptr, info_ptr, trans, npalette-1, png_set_tRNS(png_ptr, info_ptr, trans, npalette-1,
NULL/*transparent color*/); NULL/*transparent color*/);
@ -561,7 +698,7 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
for (y=0; y<size; ++y) for (y=0; y<size; ++y)
{ {
generate_row(row, rowbytes, y, color_type, bit_depth, generate_row(row, rowbytes, y, color_type, bit_depth,
gamma_table, conv); gamma_table, conv, colors);
png_write_row(png_ptr, row); png_write_row(png_ptr, row);
} }
} }
@ -1094,6 +1231,48 @@ find_insert(png_const_charp what, png_charp param)
return NULL; return NULL;
} }
/* This is a not-very-good parser for a sequence of numbers (including 0). It
* doesn't accept some apparenly valid things, but it accepts all the sensible
* combinations.
*/
static void
parse_color(char *arg, unsigned int *colors)
{
unsigned int ncolors = 0;
while (*arg && ncolors < 4)
{
char *ep = arg;
unsigned long ul = strtoul(arg, &ep, 0);
if (ul > 65535)
{
fprintf(stderr, "makepng --color=...'%s': too big\n", arg);
exit(1);
}
if (ep == arg)
{
fprintf(stderr, "makepng --color=...'%s': not a valid color\n", arg);
exit(1);
}
if (*ep) ++ep; /* skip a separator */
arg = ep;
colors[++ncolors] = (unsigned int)ul; /* checked above */
}
if (*arg)
{
fprintf(stderr, "makepng --color=...'%s': too many values\n", arg);
exit(1);
}
*colors = ncolors;
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -1101,14 +1280,17 @@ main(int argc, char **argv)
const char *file_name = NULL; const char *file_name = NULL;
int color_type = 8; /* invalid */ int color_type = 8; /* invalid */
int bit_depth = 32; /* invalid */ int bit_depth = 32; /* invalid */
unsigned int colors[5];
unsigned int filters = PNG_ALL_FILTERS; unsigned int filters = PNG_ALL_FILTERS;
png_fixed_point gamma = 0; /* not set */ png_fixed_point gamma = 0; /* not set */
chunk_insert *head_insert = NULL; chunk_insert *head_insert = NULL;
chunk_insert **insert_ptr = &head_insert; chunk_insert **insert_ptr = &head_insert;
memset(colors, 0, sizeof colors);
while (--argc > 0) while (--argc > 0)
{ {
const char *arg = *++argv; char *arg = *++argv;
if (strcmp(arg, "--sRGB") == 0) if (strcmp(arg, "--sRGB") == 0)
{ {
@ -1134,6 +1316,12 @@ main(int argc, char **argv)
continue; continue;
} }
if (strncmp(arg, "--color=", 8) == 0)
{
parse_color(arg+8, colors);
continue;
}
if (argc >= 3 && strcmp(arg, "--insert") == 0) if (argc >= 3 && strcmp(arg, "--insert") == 0)
{ {
png_const_charp what = *++argv; png_const_charp what = *++argv;
@ -1245,11 +1433,26 @@ main(int argc, char **argv)
if (color_type == 8 || bit_depth == 32) if (color_type == 8 || bit_depth == 32)
{ {
fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] " fprintf(stderr, "usage: makepng [--sRGB|--linear|--1.8] "
"color-type bit-depth [file-name]\n" "[--color=...] color-type bit-depth [file-name]\n"
" Make a test PNG file, by default writes to stdout.\n"); " Make a test PNG file, by default writes to stdout.\n");
exit(1); exit(1);
} }
/* Check the colors */
{
const unsigned int lim = (color_type == PNG_COLOR_TYPE_PALETTE ? 255U :
(1U<<bit_depth)-1);
unsigned int i;
for (i=1; i<=colors[0]; ++i)
if (colors[i] > lim)
{
fprintf(stderr, "makepng: --color=...: %u out of range [0..%u]\n",
colors[i], lim);
exit(1);
}
}
/* Restrict the filters for more speed to those we know are used for the /* Restrict the filters for more speed to those we know are used for the
* generated images. * generated images.
*/ */
@ -1273,7 +1476,7 @@ main(int argc, char **argv)
{ {
int ret = write_png(&file_name, fp, color_type, bit_depth, gamma, int ret = write_png(&file_name, fp, color_type, bit_depth, gamma,
head_insert, filters); head_insert, filters, colors);
if (ret != 0 && file_name != NULL) if (ret != 0 && file_name != NULL)
remove(file_name); remove(file_name);