mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00
Test changes
Most of these are back-portable to earlier versions (contrib/libtests should just work with earlier versions), however the 1.7 specific changes in pngvalid mean that it probably won't work against 1.7 without the commits following this one. Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
@@ -87,7 +87,7 @@ print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
|
||||
*/
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
{
|
||||
PNG_CONST unsigned int index = component(row, x, 0, bit_depth, 1);
|
||||
PNG_CONST int index = component(row, x, 0, bit_depth, 1);
|
||||
png_colorp palette = NULL;
|
||||
int num_palette = 0;
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ typedef struct chunk_insert
|
||||
png_charp parameters[1];
|
||||
} chunk_insert;
|
||||
|
||||
static int
|
||||
static unsigned int
|
||||
channels_of_type(int color_type)
|
||||
{
|
||||
if (color_type & PNG_COLOR_MASK_PALETTE)
|
||||
@@ -128,7 +128,7 @@ channels_of_type(int color_type)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static unsigned int
|
||||
pixel_depth_of_type(int color_type, int bit_depth)
|
||||
{
|
||||
return channels_of_type(color_type) * bit_depth;
|
||||
@@ -682,7 +682,11 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
|
||||
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters);
|
||||
|
||||
{
|
||||
int passes = png_set_interlace_handling(png_ptr);
|
||||
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||
int passes = png_set_interlace_handling(png_ptr);
|
||||
# else /* !WRITE_INTERLACING */
|
||||
int passes = 1;
|
||||
# endif /* !WRITE_INTERLACING */
|
||||
int pass;
|
||||
png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
|
||||
@@ -236,10 +236,12 @@ static struct transform_info
|
||||
*/
|
||||
#endif
|
||||
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
|
||||
T(SCALE_16, NONE, X, X, 16, R)
|
||||
T(SCALE_16, NONE, X, X, 16, R),
|
||||
/* scales 16-bit components to 8-bits. */
|
||||
#endif
|
||||
|
||||
{ NULL /*name*/, 0, 0, 0, 0, 0, 0, 0/*!tested*/ }
|
||||
|
||||
#undef T
|
||||
};
|
||||
|
||||
@@ -294,7 +296,7 @@ transform_name(int t)
|
||||
|
||||
t &= -t; /* first set bit */
|
||||
|
||||
for (i=0; i<TTABLE_SIZE; ++i)
|
||||
for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
|
||||
{
|
||||
if ((transform_info[i].transform & t) != 0)
|
||||
return transform_info[i].name;
|
||||
@@ -315,7 +317,7 @@ validate_T(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; i<TTABLE_SIZE; ++i)
|
||||
for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
|
||||
{
|
||||
if (transform_info[i].when & TRANSFORM_R)
|
||||
read_transforms |= transform_info[i].transform;
|
||||
@@ -505,6 +507,7 @@ typedef enum
|
||||
#define SKIP_BUGS 0x100 /* Skip over known bugs */
|
||||
#define LOG_SKIPPED 0x200 /* Log skipped bugs */
|
||||
#define FIND_BAD_COMBOS 0x400 /* Attempt to deduce bad combos */
|
||||
#define LIST_COMBOS 0x800 /* List combos by name */
|
||||
|
||||
/* Result masks apply to the result bits in the 'results' field below; these
|
||||
* bits are simple 1U<<error_level. A pass requires either nothing worse than
|
||||
@@ -690,7 +693,35 @@ display_log(struct display *dp, error_level level, const char *fmt, ...)
|
||||
int tr = dp->transforms;
|
||||
|
||||
if (is_combo(tr))
|
||||
fprintf(stderr, "(0x%x)", tr);
|
||||
{
|
||||
if (dp->options & LIST_COMBOS)
|
||||
{
|
||||
int trx = tr;
|
||||
|
||||
fprintf(stderr, "(");
|
||||
if (trx)
|
||||
{
|
||||
int start = 0;
|
||||
|
||||
while (trx)
|
||||
{
|
||||
int trz = trx & -trx;
|
||||
|
||||
if (start) fprintf(stderr, "+");
|
||||
fprintf(stderr, "%s", transform_name(trz));
|
||||
start = 1;
|
||||
trx &= ~trz;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
fprintf(stderr, "-");
|
||||
fprintf(stderr, ")");
|
||||
}
|
||||
|
||||
else
|
||||
fprintf(stderr, "(0x%x)", tr);
|
||||
}
|
||||
|
||||
else
|
||||
fprintf(stderr, "(%s)", transform_name(tr));
|
||||
@@ -910,7 +941,7 @@ update_display(struct display *dp)
|
||||
int bd = dp->bit_depth;
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; i<TTABLE_SIZE; ++i)
|
||||
for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
|
||||
{
|
||||
int transform = transform_info[i].transform;
|
||||
|
||||
@@ -935,9 +966,6 @@ update_display(struct display *dp)
|
||||
|
||||
dp->active_transforms = active;
|
||||
dp->ignored_transforms = inactive; /* excluding write-only transforms */
|
||||
|
||||
if (active == 0)
|
||||
display_log(dp, INTERNAL_ERROR, "bad transform table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1588,6 +1616,12 @@ main(const int argc, const char * const * const argv)
|
||||
else if (strcmp(name, "--nofind-bad-combos") == 0)
|
||||
d.options &= ~FIND_BAD_COMBOS;
|
||||
|
||||
else if (strcmp(name, "--list-combos") == 0)
|
||||
d.options |= LIST_COMBOS;
|
||||
|
||||
else if (strcmp(name, "--nolist-combos") == 0)
|
||||
d.options &= ~LIST_COMBOS;
|
||||
|
||||
else if (name[0] == '-' && name[1] == '-')
|
||||
{
|
||||
fprintf(stderr, "pngimage: %s: unknown option\n", name);
|
||||
|
||||
@@ -363,7 +363,7 @@ ancillary(const char *name)
|
||||
return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3]));
|
||||
}
|
||||
|
||||
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
static int
|
||||
ancillaryb(const png_byte *name)
|
||||
{
|
||||
@@ -554,7 +554,7 @@ read_callback(png_structp pp, png_unknown_chunkp pc)
|
||||
/* However if there is no support to store unknown chunks don't ask libpng to
|
||||
* do it; there will be an png_error.
|
||||
*/
|
||||
# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
return discard;
|
||||
# else
|
||||
return 1; /*handled; discard*/
|
||||
@@ -562,7 +562,7 @@ read_callback(png_structp pp, png_unknown_chunkp pc)
|
||||
}
|
||||
#endif /* READ_USER_CHUNKS_SUPPORTED */
|
||||
|
||||
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
static png_uint_32
|
||||
get_unknown(display *d, png_infop info_ptr, int after_IDAT)
|
||||
{
|
||||
@@ -722,11 +722,17 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
|
||||
* in this case, so we just check the arguments! This could
|
||||
* be improved in the future by using the read callback.
|
||||
*/
|
||||
png_byte name[5];
|
||||
# if PNG_LIBPNG_VER >= 10700 &&\
|
||||
!defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
|
||||
if (option < PNG_HANDLE_CHUNK_IF_SAFE)
|
||||
# endif /* 1.7+ SAVE_UNKNOWN_CHUNKS */
|
||||
{
|
||||
png_byte name[5];
|
||||
|
||||
memcpy(name, chunk_info[chunk].name, 5);
|
||||
png_set_keep_unknown_chunks(d->png_ptr, option, name, 1);
|
||||
chunk_info[chunk].keep = option;
|
||||
memcpy(name, chunk_info[chunk].name, 5);
|
||||
png_set_keep_unknown_chunks(d->png_ptr, option, name, 1);
|
||||
chunk_info[chunk].keep = option;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -735,7 +741,12 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
|
||||
case 7: /* default */
|
||||
if (memcmp(argv[i], "default", 7) == 0)
|
||||
{
|
||||
png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0);
|
||||
# if PNG_LIBPNG_VER >= 10700 &&\
|
||||
!defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
|
||||
if (option < PNG_HANDLE_CHUNK_IF_SAFE)
|
||||
# endif /* 1.7+ SAVE_UNKNOWN_CHUNKS */
|
||||
png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0);
|
||||
|
||||
d->keep = option;
|
||||
continue;
|
||||
}
|
||||
@@ -745,7 +756,12 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
|
||||
case 3: /* all */
|
||||
if (memcmp(argv[i], "all", 3) == 0)
|
||||
{
|
||||
png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1);
|
||||
# if PNG_LIBPNG_VER >= 10700 &&\
|
||||
!defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
|
||||
if (option < PNG_HANDLE_CHUNK_IF_SAFE)
|
||||
# endif /* 1.7+ SAVE_UNKNOWN_CHUNKS */
|
||||
png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1);
|
||||
|
||||
d->keep = option;
|
||||
|
||||
for (chunk = 0; chunk < NINFO; ++chunk)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -70,7 +70,12 @@ read_png(FILE *fp)
|
||||
|
||||
{
|
||||
png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
|
||||
int passes = png_set_interlace_handling(png_ptr);
|
||||
# ifdef PNG_READ_DEINTERLACE_SUPPORTED
|
||||
int passes = png_set_interlace_handling(png_ptr);
|
||||
# else
|
||||
int passes = png_get_interlace_type(png_ptr, info_ptr) ==
|
||||
PNG_INTERLACE_ADAM7 ? PNG_INTERLACE_ADAM7_PASSES : 1;
|
||||
# endif
|
||||
int pass;
|
||||
|
||||
png_start_read_image(png_ptr);
|
||||
@@ -79,6 +84,11 @@ read_png(FILE *fp)
|
||||
{
|
||||
png_uint_32 y = height;
|
||||
|
||||
# ifndef PNG_READ_DEINTERLACE_SUPPORTED
|
||||
if (passes == PNG_INTERLACE_ADAM7_PASSES)
|
||||
y = PNG_PASS_ROWS(y, pass);
|
||||
# endif
|
||||
|
||||
/* NOTE: this trashes the row each time; interlace handling won't
|
||||
* work, but this avoids memory thrashing for speed testing.
|
||||
*/
|
||||
|
||||
208
contrib/tools/dynamic-range.c
Normal file
208
contrib/tools/dynamic-range.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/* dynamic-range.c
|
||||
*
|
||||
* Last changed in libpng 1.7.0
|
||||
*
|
||||
* COPYRIGHT: Written by John Cunningham Bowler, 2015
|
||||
* To the extent possible under law, the author has waived all copyright and
|
||||
* related or neighboring rights to this work. This work is published from:
|
||||
* United States.
|
||||
*
|
||||
* Find the dynamic range of a given gamma encoding given a (linear) precision
|
||||
* and a maximum number of encoded values.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
double range(unsigned int steps, double factor, double gamma)
|
||||
{
|
||||
return pow((steps * (pow(factor, 1/gamma) - 1)), gamma);
|
||||
}
|
||||
|
||||
double max_range_gamma(unsigned int steps, double factor, double *max_range,
|
||||
double glo, double rlo, double gmid, double rmid, double ghi, double rhi)
|
||||
{
|
||||
/* Given three values which contain a peak value (so rmid > rlo and rmid >
|
||||
* rhi) find the peak by repeated division of the range. The algorithm is to
|
||||
* find the range for two gamma values mid-way between the two pairs
|
||||
* (glo,gmid), (ghi,gmid) then find the max; this gives us a new glo/ghi
|
||||
* which must be half the distance apart of the previous pair.
|
||||
*/
|
||||
double gammas[5];
|
||||
double ranges[5];
|
||||
|
||||
gammas[0] = glo; ranges[0] = rlo;
|
||||
gammas[2] = gmid; ranges[2] = rmid;
|
||||
gammas[4] = ghi; ranges[4] = rhi;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int i, m;
|
||||
|
||||
ranges[1] = range(steps, factor, gammas[1] = (gammas[0]+gammas[2])/2);
|
||||
ranges[3] = range(steps, factor, gammas[3] = (gammas[2]+gammas[4])/2);
|
||||
|
||||
for (m=1, i=2; i<4; ++i)
|
||||
if (ranges[i] >= ranges[m])
|
||||
m = i;
|
||||
|
||||
assert(gammas[0] < gammas[m] && gammas[m] < gammas[4]);
|
||||
assert(ranges[0] < ranges[m] && ranges[m] > ranges[4]);
|
||||
|
||||
gammas[0] = gammas[m-1]; ranges[0] = ranges[m-1];
|
||||
gammas[4] = gammas[m+1]; ranges[4] = ranges[m+1];
|
||||
gammas[2] = gammas[m]; ranges[2] = ranges[m];
|
||||
|
||||
if (((gammas[4] - gammas[0])/gammas[2]-1) < 3*DBL_EPSILON ||
|
||||
((ranges[2] - ranges[0])/ranges[2]-1) < 6*DBL_EPSILON)
|
||||
{
|
||||
*max_range = ranges[2];
|
||||
return gammas[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double best_gamma(unsigned int values, double precision, double *best_range)
|
||||
{
|
||||
/* The 'guess' gamma value is determined by the following formula, which is
|
||||
* itself derived from linear regression using values returned by this
|
||||
* program:
|
||||
*/
|
||||
double gtry = values * precision / 2.736;
|
||||
double rtry;
|
||||
|
||||
/* 'values' needs to be the number of steps after the first, we have to
|
||||
* reserve the first value, 0, for 0, so subtract 2 from values. precision
|
||||
* must be adjusted to the step factor.
|
||||
*/
|
||||
values -= 2U;
|
||||
precision += 1;
|
||||
rtry = range(values, precision, gtry);
|
||||
|
||||
/* Now find two values either side of gtry with a lower range. */
|
||||
{
|
||||
double glo, ghi, rlo, rhi, gbest, rbest;
|
||||
|
||||
glo = gtry;
|
||||
do
|
||||
{
|
||||
glo *= 0.9;
|
||||
rlo = range(values, precision, glo);
|
||||
}
|
||||
while (rlo >= rtry);
|
||||
|
||||
ghi = gtry;
|
||||
do
|
||||
{
|
||||
ghi *= 1.1;
|
||||
rhi = range(values, precision, ghi);
|
||||
}
|
||||
while (rhi >= rtry);
|
||||
|
||||
gbest = max_range_gamma(values, precision, &rbest,
|
||||
glo, rlo, gtry, rtry, ghi, rhi);
|
||||
|
||||
*best_range = rbest / precision;
|
||||
return gbest;
|
||||
}
|
||||
}
|
||||
|
||||
double linear_regression(double precision, double *bp)
|
||||
{
|
||||
unsigned int values, count = 0;
|
||||
double g_sum = 0, g2_sum = 0, v_sum = 0, v2_sum = 0, gv_sum = 0;
|
||||
|
||||
/* Perform simple linear regression to get:
|
||||
*
|
||||
* gamma = a + b.values
|
||||
*/
|
||||
for (values = 128; values < 65536; ++values, ++count)
|
||||
{
|
||||
double range;
|
||||
double gamma = best_gamma(values, precision, &range);
|
||||
|
||||
g_sum += gamma;
|
||||
g2_sum += gamma * gamma;
|
||||
v_sum += values;
|
||||
v2_sum += values * (double)values;
|
||||
gv_sum += gamma * values;
|
||||
/* printf("%u %g %g\n", values, gamma, range); */
|
||||
}
|
||||
|
||||
g_sum /= count;
|
||||
g2_sum /= count;
|
||||
v_sum /= count;
|
||||
v2_sum /= count;
|
||||
gv_sum /= count;
|
||||
|
||||
{
|
||||
double b = (gv_sum - g_sum * v_sum) / (v2_sum - v_sum * v_sum);
|
||||
*bp = b;
|
||||
return g_sum - b * v_sum;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
double precision = argc == 2 ? atof(argv[1]) : 0;
|
||||
|
||||
/* Perform a second linear regression here on b:
|
||||
*
|
||||
* b = bA + bB * precision
|
||||
*/
|
||||
if (precision == 0)
|
||||
{
|
||||
double b_sum = 0, b2_sum = 0, p_sum = 0, p2_sum = 0, bp_sum = 0,
|
||||
a_sum = 0, count = 0;
|
||||
|
||||
for (precision = .001; precision <= 0.01; precision += .001, count += 1)
|
||||
{
|
||||
double b;
|
||||
double a = linear_regression(precision, &b);
|
||||
|
||||
b_sum += b;
|
||||
b2_sum += b * b;
|
||||
p_sum += precision;
|
||||
p2_sum += precision * precision;
|
||||
bp_sum += b * precision;
|
||||
a_sum += a;
|
||||
}
|
||||
|
||||
b_sum /= count;
|
||||
b2_sum /= count;
|
||||
p_sum /= count;
|
||||
p2_sum /= count;
|
||||
bp_sum /= count;
|
||||
a_sum /= count;
|
||||
|
||||
{
|
||||
double bB = (bp_sum - b_sum * p_sum) / (p2_sum - p_sum * p_sum);
|
||||
double bA = b_sum - bB * p_sum;
|
||||
|
||||
printf("a = %g, b = %g + precision/%g\n", a_sum, bA, 1/bB);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
unsigned int bits;
|
||||
double b;
|
||||
double a = linear_regression(precision, &b);
|
||||
printf("precision %g: gamma = %g + values*%g\n", precision, a, b);
|
||||
|
||||
/* For information, given a precision: */
|
||||
for (bits=7U; bits <= 16U; ++bits)
|
||||
{
|
||||
unsigned int values = 1U<<bits;
|
||||
double gamma = values*precision/2.736;
|
||||
double r = range(values-2U, 1+precision, gamma);
|
||||
|
||||
printf("bits: %u, gamma: %g, range: 1:%g\n", bits, gamma, r);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -52,7 +52,8 @@
|
||||
#ifdef PNG_SETJMP_SUPPORTED
|
||||
#include <setjmp.h>
|
||||
|
||||
#if defined(PNG_READ_SUPPORTED) && defined(PNG_EASY_ACCESS_SUPPORTED)
|
||||
#if defined(PNG_READ_SUPPORTED) && defined(PNG_EASY_ACCESS_SUPPORTED) &&\
|
||||
defined(PNG_READ_DEINTERLACE_SUPPORTED)
|
||||
/* zlib.h defines the structure z_stream, an instance of which is included
|
||||
* in this structure and is required for decompressing the LZ compressed
|
||||
* data in PNG files.
|
||||
@@ -4030,7 +4031,7 @@ main(void)
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
fprintf(stderr, "pngfix does not work without read support\n");
|
||||
fprintf(stderr, "pngfix does not work without read deinterlace support\n");
|
||||
return 77;
|
||||
}
|
||||
#endif /* PNG_READ_SUPPORTED && PNG_EASY_ACCESS_SUPPORTED */
|
||||
@@ -4042,4 +4043,3 @@ main(void)
|
||||
return 77;
|
||||
}
|
||||
#endif /* PNG_SETJMP_SUPPORTED */
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/*===
|
||||
cexcept.h 2.0.1 (2008-Jul-19-Sat, modified 2015-Jun-03-Mon)
|
||||
cexcept.h 2.0.1 (2008-Jul-19-Sat)
|
||||
http://www.nicemice.net/cexcept/
|
||||
Adam M. Costello
|
||||
http://www.nicemice.net/amc/
|
||||
|
||||
An interface for exception-handling in ANSI C (C89 and subsequent ISO
|
||||
standards), developed jointly with Cosmin Truta. Revised by John Bowler,
|
||||
June 2015, to declare exception_env and exception_prev "volatile".
|
||||
standards), developed jointly with Cosmin Truta.
|
||||
|
||||
Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta.
|
||||
This software may be modified only if its author and version
|
||||
@@ -211,7 +210,7 @@ struct exception_context { \
|
||||
|
||||
#define Try \
|
||||
{ \
|
||||
jmp_buf * volatile exception__prev, exception__env; \
|
||||
jmp_buf *exception__prev, exception__env; \
|
||||
exception__prev = the_exception_context->penv; \
|
||||
the_exception_context->penv = &exception__env; \
|
||||
if (setjmp(exception__env) == 0) { \
|
||||
|
||||
Reference in New Issue
Block a user