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:
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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user