xref: /aosp_15_r20/external/libpng/contrib/tools/makesRGB.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
1*a67afe4dSAndroid Build Coastguard Worker /* makesRGB.c -- build sRGB-to-linear and linear-to-sRGB conversion tables
2*a67afe4dSAndroid Build Coastguard Worker  *
3*a67afe4dSAndroid Build Coastguard Worker  * COPYRIGHT: Written by John Cunningham Bowler, 2013.
4*a67afe4dSAndroid Build Coastguard Worker  * To the extent possible under law, the author has waived all copyright and
5*a67afe4dSAndroid Build Coastguard Worker  * related or neighboring rights to this work.  This work is published from:
6*a67afe4dSAndroid Build Coastguard Worker  * United States.
7*a67afe4dSAndroid Build Coastguard Worker  *
8*a67afe4dSAndroid Build Coastguard Worker  * Make a table to convert 8-bit sRGB encoding values into the closest 16-bit
9*a67afe4dSAndroid Build Coastguard Worker  * linear value.
10*a67afe4dSAndroid Build Coastguard Worker  *
11*a67afe4dSAndroid Build Coastguard Worker  * Make two tables to take a linear value scaled to 255*65535 and return an
12*a67afe4dSAndroid Build Coastguard Worker  * approximation to the 8-bit sRGB encoded value.  Calculate the error in these
13*a67afe4dSAndroid Build Coastguard Worker  * tables and display it.
14*a67afe4dSAndroid Build Coastguard Worker  */
15*a67afe4dSAndroid Build Coastguard Worker 
16*a67afe4dSAndroid Build Coastguard Worker #define _C99_SOURCE 1
17*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
18*a67afe4dSAndroid Build Coastguard Worker #include <math.h>
19*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
20*a67afe4dSAndroid Build Coastguard Worker 
21*a67afe4dSAndroid Build Coastguard Worker /* pngpriv.h includes the definition of 'PNG_sRGB_FROM_LINEAR' which is required
22*a67afe4dSAndroid Build Coastguard Worker  * to verify the actual code.
23*a67afe4dSAndroid Build Coastguard Worker  */
24*a67afe4dSAndroid Build Coastguard Worker #include "../../pngpriv.h"
25*a67afe4dSAndroid Build Coastguard Worker 
26*a67afe4dSAndroid Build Coastguard Worker #include "sRGB.h"
27*a67afe4dSAndroid Build Coastguard Worker 
28*a67afe4dSAndroid Build Coastguard Worker /* The tables are declared 'const' in pngpriv.h, so this redefines the tables to
29*a67afe4dSAndroid Build Coastguard Worker  * be used.
30*a67afe4dSAndroid Build Coastguard Worker  */
31*a67afe4dSAndroid Build Coastguard Worker #define png_sRGB_table sRGB_table
32*a67afe4dSAndroid Build Coastguard Worker #define png_sRGB_base sRGB_base
33*a67afe4dSAndroid Build Coastguard Worker #define png_sRGB_delta sRGB_delta
34*a67afe4dSAndroid Build Coastguard Worker 
35*a67afe4dSAndroid Build Coastguard Worker static png_uint_16 png_sRGB_table[256];
36*a67afe4dSAndroid Build Coastguard Worker static png_uint_16 png_sRGB_base[512];
37*a67afe4dSAndroid Build Coastguard Worker static png_byte png_sRGB_delta[512];
38*a67afe4dSAndroid Build Coastguard Worker 
39*a67afe4dSAndroid Build Coastguard Worker static const unsigned int max_input = 255*65535;
40*a67afe4dSAndroid Build Coastguard Worker 
41*a67afe4dSAndroid Build Coastguard Worker double
fsRGB(double l)42*a67afe4dSAndroid Build Coastguard Worker fsRGB(double l)
43*a67afe4dSAndroid Build Coastguard Worker {
44*a67afe4dSAndroid Build Coastguard Worker    return sRGB_from_linear(l/max_input);
45*a67afe4dSAndroid Build Coastguard Worker }
46*a67afe4dSAndroid Build Coastguard Worker 
47*a67afe4dSAndroid Build Coastguard Worker double
sRGB(unsigned int i)48*a67afe4dSAndroid Build Coastguard Worker sRGB(unsigned int i)
49*a67afe4dSAndroid Build Coastguard Worker {
50*a67afe4dSAndroid Build Coastguard Worker    return fsRGB(i);
51*a67afe4dSAndroid Build Coastguard Worker }
52*a67afe4dSAndroid Build Coastguard Worker 
53*a67afe4dSAndroid Build Coastguard Worker double
finvsRGB(unsigned int i)54*a67afe4dSAndroid Build Coastguard Worker finvsRGB(unsigned int i)
55*a67afe4dSAndroid Build Coastguard Worker {
56*a67afe4dSAndroid Build Coastguard Worker    return 65535 * linear_from_sRGB(i/255.);
57*a67afe4dSAndroid Build Coastguard Worker }
58*a67afe4dSAndroid Build Coastguard Worker 
59*a67afe4dSAndroid Build Coastguard Worker png_uint_16
invsRGB(unsigned int i)60*a67afe4dSAndroid Build Coastguard Worker invsRGB(unsigned int i)
61*a67afe4dSAndroid Build Coastguard Worker {
62*a67afe4dSAndroid Build Coastguard Worker    unsigned int x = nearbyint(finvsRGB(i));
63*a67afe4dSAndroid Build Coastguard Worker 
64*a67afe4dSAndroid Build Coastguard Worker    if (x > 65535)
65*a67afe4dSAndroid Build Coastguard Worker    {
66*a67afe4dSAndroid Build Coastguard Worker       fprintf(stderr, "invsRGB(%u) overflows to %u\n", i, x);
67*a67afe4dSAndroid Build Coastguard Worker       exit(1);
68*a67afe4dSAndroid Build Coastguard Worker    }
69*a67afe4dSAndroid Build Coastguard Worker 
70*a67afe4dSAndroid Build Coastguard Worker    return (png_uint_16)x;
71*a67afe4dSAndroid Build Coastguard Worker }
72*a67afe4dSAndroid Build Coastguard Worker 
73*a67afe4dSAndroid Build Coastguard Worker int
main(int argc,char ** argv)74*a67afe4dSAndroid Build Coastguard Worker main(int argc, char **argv)
75*a67afe4dSAndroid Build Coastguard Worker {
76*a67afe4dSAndroid Build Coastguard Worker    unsigned int i, i16, ibase;
77*a67afe4dSAndroid Build Coastguard Worker    double min_error = 0;
78*a67afe4dSAndroid Build Coastguard Worker    double max_error = 0;
79*a67afe4dSAndroid Build Coastguard Worker    double min_error16 = 0;
80*a67afe4dSAndroid Build Coastguard Worker    double max_error16 = 0;
81*a67afe4dSAndroid Build Coastguard Worker    double adjust;
82*a67afe4dSAndroid Build Coastguard Worker    double adjust_lo = 0.4, adjust_hi = 0.6, adjust_mid = 0.5;
83*a67afe4dSAndroid Build Coastguard Worker    unsigned int ec_lo = 0, ec_hi = 0, ec_mid = 0;
84*a67afe4dSAndroid Build Coastguard Worker    unsigned int error_count = 0;
85*a67afe4dSAndroid Build Coastguard Worker    unsigned int error_count16 = 0;
86*a67afe4dSAndroid Build Coastguard Worker    int test_only = 0;
87*a67afe4dSAndroid Build Coastguard Worker 
88*a67afe4dSAndroid Build Coastguard Worker    if (argc > 1)
89*a67afe4dSAndroid Build Coastguard Worker       test_only = strcmp("--test", argv[1]) == 0;
90*a67afe4dSAndroid Build Coastguard Worker 
91*a67afe4dSAndroid Build Coastguard Worker    /* Initialize the encoding table first. */
92*a67afe4dSAndroid Build Coastguard Worker    for (i=0; i<256; ++i)
93*a67afe4dSAndroid Build Coastguard Worker    {
94*a67afe4dSAndroid Build Coastguard Worker       png_sRGB_table[i] = invsRGB(i);
95*a67afe4dSAndroid Build Coastguard Worker    }
96*a67afe4dSAndroid Build Coastguard Worker 
97*a67afe4dSAndroid Build Coastguard Worker    /* Now work out the decoding tables (this is where the error comes in because
98*a67afe4dSAndroid Build Coastguard Worker     * there are 512 set points and 512 straight lines between them.)
99*a67afe4dSAndroid Build Coastguard Worker     */
100*a67afe4dSAndroid Build Coastguard Worker    for (;;)
101*a67afe4dSAndroid Build Coastguard Worker    {
102*a67afe4dSAndroid Build Coastguard Worker       if (ec_lo == 0)
103*a67afe4dSAndroid Build Coastguard Worker          adjust = adjust_lo;
104*a67afe4dSAndroid Build Coastguard Worker 
105*a67afe4dSAndroid Build Coastguard Worker       else if (ec_hi == 0)
106*a67afe4dSAndroid Build Coastguard Worker          adjust = adjust_hi;
107*a67afe4dSAndroid Build Coastguard Worker 
108*a67afe4dSAndroid Build Coastguard Worker       else if (ec_mid == 0)
109*a67afe4dSAndroid Build Coastguard Worker          adjust = adjust_mid;
110*a67afe4dSAndroid Build Coastguard Worker 
111*a67afe4dSAndroid Build Coastguard Worker       else if (ec_mid < ec_hi)
112*a67afe4dSAndroid Build Coastguard Worker          adjust = (adjust_mid + adjust_hi)/2;
113*a67afe4dSAndroid Build Coastguard Worker 
114*a67afe4dSAndroid Build Coastguard Worker       else if (ec_mid < ec_lo)
115*a67afe4dSAndroid Build Coastguard Worker          adjust = (adjust_mid + adjust_lo)/2;
116*a67afe4dSAndroid Build Coastguard Worker 
117*a67afe4dSAndroid Build Coastguard Worker       else
118*a67afe4dSAndroid Build Coastguard Worker       {
119*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "not reached: %u .. %u .. %u\n", ec_lo, ec_mid, ec_hi);
120*a67afe4dSAndroid Build Coastguard Worker          exit(1);
121*a67afe4dSAndroid Build Coastguard Worker       }
122*a67afe4dSAndroid Build Coastguard Worker 
123*a67afe4dSAndroid Build Coastguard Worker       /* Calculate the table using the current 'adjust' */
124*a67afe4dSAndroid Build Coastguard Worker       for (i=0; i<=511; ++i)
125*a67afe4dSAndroid Build Coastguard Worker       {
126*a67afe4dSAndroid Build Coastguard Worker          double lo = 255 * sRGB(i << 15);
127*a67afe4dSAndroid Build Coastguard Worker          double hi = 255 * sRGB((i+1) << 15);
128*a67afe4dSAndroid Build Coastguard Worker          unsigned int calc;
129*a67afe4dSAndroid Build Coastguard Worker 
130*a67afe4dSAndroid Build Coastguard Worker          calc = nearbyint((lo+adjust) * 256);
131*a67afe4dSAndroid Build Coastguard Worker          if (calc > 65535)
132*a67afe4dSAndroid Build Coastguard Worker          {
133*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "table[%d][0]: overflow %08x (%d)\n", i, calc,
134*a67afe4dSAndroid Build Coastguard Worker                calc);
135*a67afe4dSAndroid Build Coastguard Worker             exit(1);
136*a67afe4dSAndroid Build Coastguard Worker          }
137*a67afe4dSAndroid Build Coastguard Worker          png_sRGB_base[i] = calc;
138*a67afe4dSAndroid Build Coastguard Worker 
139*a67afe4dSAndroid Build Coastguard Worker          calc = nearbyint((hi-lo) * 32);
140*a67afe4dSAndroid Build Coastguard Worker          if (calc > 255)
141*a67afe4dSAndroid Build Coastguard Worker          {
142*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "table[%d][1]: overflow %08x (%d)\n", i, calc,
143*a67afe4dSAndroid Build Coastguard Worker                calc);
144*a67afe4dSAndroid Build Coastguard Worker             exit(1);
145*a67afe4dSAndroid Build Coastguard Worker          }
146*a67afe4dSAndroid Build Coastguard Worker          png_sRGB_delta[i] = calc;
147*a67afe4dSAndroid Build Coastguard Worker       }
148*a67afe4dSAndroid Build Coastguard Worker 
149*a67afe4dSAndroid Build Coastguard Worker       /* Check the 16-bit linear values alone: */
150*a67afe4dSAndroid Build Coastguard Worker       error_count16 = 0;
151*a67afe4dSAndroid Build Coastguard Worker       for (i16=0; i16 <= 65535; ++i16)
152*a67afe4dSAndroid Build Coastguard Worker       {
153*a67afe4dSAndroid Build Coastguard Worker          unsigned int i = 255*i16;
154*a67afe4dSAndroid Build Coastguard Worker          unsigned int iexact = nearbyint(255*sRGB(i));
155*a67afe4dSAndroid Build Coastguard Worker          unsigned int icalc = PNG_sRGB_FROM_LINEAR(i);
156*a67afe4dSAndroid Build Coastguard Worker 
157*a67afe4dSAndroid Build Coastguard Worker          if (icalc != iexact)
158*a67afe4dSAndroid Build Coastguard Worker             ++error_count16;
159*a67afe4dSAndroid Build Coastguard Worker       }
160*a67afe4dSAndroid Build Coastguard Worker 
161*a67afe4dSAndroid Build Coastguard Worker       /* Now try changing the adjustment. */
162*a67afe4dSAndroid Build Coastguard Worker       if (ec_lo == 0)
163*a67afe4dSAndroid Build Coastguard Worker          ec_lo = error_count16;
164*a67afe4dSAndroid Build Coastguard Worker 
165*a67afe4dSAndroid Build Coastguard Worker       else if (ec_hi == 0)
166*a67afe4dSAndroid Build Coastguard Worker          ec_hi = error_count16;
167*a67afe4dSAndroid Build Coastguard Worker 
168*a67afe4dSAndroid Build Coastguard Worker       else if (ec_mid == 0)
169*a67afe4dSAndroid Build Coastguard Worker       {
170*a67afe4dSAndroid Build Coastguard Worker          ec_mid = error_count16;
171*a67afe4dSAndroid Build Coastguard Worker          printf("/* initial error counts: %u .. %u .. %u */\n", ec_lo, ec_mid,
172*a67afe4dSAndroid Build Coastguard Worker             ec_hi);
173*a67afe4dSAndroid Build Coastguard Worker       }
174*a67afe4dSAndroid Build Coastguard Worker 
175*a67afe4dSAndroid Build Coastguard Worker       else if (error_count16 < ec_mid)
176*a67afe4dSAndroid Build Coastguard Worker       {
177*a67afe4dSAndroid Build Coastguard Worker          printf("/* adjust (mid ): %f: %u -> %u */\n", adjust, ec_mid,
178*a67afe4dSAndroid Build Coastguard Worker             error_count16);
179*a67afe4dSAndroid Build Coastguard Worker          ec_mid = error_count16;
180*a67afe4dSAndroid Build Coastguard Worker          adjust_mid = adjust;
181*a67afe4dSAndroid Build Coastguard Worker       }
182*a67afe4dSAndroid Build Coastguard Worker 
183*a67afe4dSAndroid Build Coastguard Worker       else if (adjust < adjust_mid && error_count16 < ec_lo)
184*a67afe4dSAndroid Build Coastguard Worker       {
185*a67afe4dSAndroid Build Coastguard Worker          printf("/* adjust (low ): %f: %u -> %u */\n", adjust, ec_lo,
186*a67afe4dSAndroid Build Coastguard Worker             error_count16);
187*a67afe4dSAndroid Build Coastguard Worker          ec_lo = error_count16;
188*a67afe4dSAndroid Build Coastguard Worker          adjust_lo = adjust;
189*a67afe4dSAndroid Build Coastguard Worker       }
190*a67afe4dSAndroid Build Coastguard Worker 
191*a67afe4dSAndroid Build Coastguard Worker       else if (adjust > adjust_mid && error_count16 < ec_hi)
192*a67afe4dSAndroid Build Coastguard Worker       {
193*a67afe4dSAndroid Build Coastguard Worker          printf("/* adjust (high): %f: %u -> %u */\n", adjust, ec_hi,
194*a67afe4dSAndroid Build Coastguard Worker             error_count16);
195*a67afe4dSAndroid Build Coastguard Worker          ec_hi = error_count16;
196*a67afe4dSAndroid Build Coastguard Worker          adjust_hi = adjust;
197*a67afe4dSAndroid Build Coastguard Worker       }
198*a67afe4dSAndroid Build Coastguard Worker 
199*a67afe4dSAndroid Build Coastguard Worker       else
200*a67afe4dSAndroid Build Coastguard Worker       {
201*a67afe4dSAndroid Build Coastguard Worker          adjust = adjust_mid;
202*a67afe4dSAndroid Build Coastguard Worker          printf("/* adjust: %f: %u */\n", adjust, ec_mid);
203*a67afe4dSAndroid Build Coastguard Worker          break;
204*a67afe4dSAndroid Build Coastguard Worker       }
205*a67afe4dSAndroid Build Coastguard Worker    }
206*a67afe4dSAndroid Build Coastguard Worker 
207*a67afe4dSAndroid Build Coastguard Worker    /* For each entry in the table try to adjust it to minimize the error count
208*a67afe4dSAndroid Build Coastguard Worker     * in that entry.  Each entry corresponds to 128 input values.
209*a67afe4dSAndroid Build Coastguard Worker     */
210*a67afe4dSAndroid Build Coastguard Worker    for (ibase=0; ibase<65536; ibase+=128)
211*a67afe4dSAndroid Build Coastguard Worker    {
212*a67afe4dSAndroid Build Coastguard Worker       png_uint_16 base = png_sRGB_base[ibase >> 7], trybase = base, ob=base;
213*a67afe4dSAndroid Build Coastguard Worker       png_byte delta = png_sRGB_delta[ibase >> 7], trydelta = delta, od=delta;
214*a67afe4dSAndroid Build Coastguard Worker       unsigned int ecbase = 0, eco;
215*a67afe4dSAndroid Build Coastguard Worker 
216*a67afe4dSAndroid Build Coastguard Worker       for (;;)
217*a67afe4dSAndroid Build Coastguard Worker       {
218*a67afe4dSAndroid Build Coastguard Worker          png_sRGB_base[ibase >> 7] = trybase;
219*a67afe4dSAndroid Build Coastguard Worker          png_sRGB_delta[ibase >> 7] = trydelta;
220*a67afe4dSAndroid Build Coastguard Worker 
221*a67afe4dSAndroid Build Coastguard Worker          /* Check the 16-bit linear values alone: */
222*a67afe4dSAndroid Build Coastguard Worker          error_count16 = 0;
223*a67afe4dSAndroid Build Coastguard Worker          for (i16=ibase; i16 < ibase+128; ++i16)
224*a67afe4dSAndroid Build Coastguard Worker          {
225*a67afe4dSAndroid Build Coastguard Worker             unsigned int i = 255*i16;
226*a67afe4dSAndroid Build Coastguard Worker             unsigned int iexact = nearbyint(255*sRGB(i));
227*a67afe4dSAndroid Build Coastguard Worker             unsigned int icalc = PNG_sRGB_FROM_LINEAR(i);
228*a67afe4dSAndroid Build Coastguard Worker 
229*a67afe4dSAndroid Build Coastguard Worker             if (icalc != iexact)
230*a67afe4dSAndroid Build Coastguard Worker                ++error_count16;
231*a67afe4dSAndroid Build Coastguard Worker          }
232*a67afe4dSAndroid Build Coastguard Worker 
233*a67afe4dSAndroid Build Coastguard Worker          if (error_count16 == 0)
234*a67afe4dSAndroid Build Coastguard Worker             break;
235*a67afe4dSAndroid Build Coastguard Worker 
236*a67afe4dSAndroid Build Coastguard Worker          if (ecbase == 0)
237*a67afe4dSAndroid Build Coastguard Worker          {
238*a67afe4dSAndroid Build Coastguard Worker             eco = ecbase = error_count16;
239*a67afe4dSAndroid Build Coastguard Worker             ++trybase; /* First test */
240*a67afe4dSAndroid Build Coastguard Worker          }
241*a67afe4dSAndroid Build Coastguard Worker 
242*a67afe4dSAndroid Build Coastguard Worker          else if (error_count16 < ecbase)
243*a67afe4dSAndroid Build Coastguard Worker          {
244*a67afe4dSAndroid Build Coastguard Worker             if (trybase > base)
245*a67afe4dSAndroid Build Coastguard Worker             {
246*a67afe4dSAndroid Build Coastguard Worker                base = trybase;
247*a67afe4dSAndroid Build Coastguard Worker                ++trybase;
248*a67afe4dSAndroid Build Coastguard Worker             }
249*a67afe4dSAndroid Build Coastguard Worker             else if (trybase < base)
250*a67afe4dSAndroid Build Coastguard Worker             {
251*a67afe4dSAndroid Build Coastguard Worker                base = trybase;
252*a67afe4dSAndroid Build Coastguard Worker                --trybase;
253*a67afe4dSAndroid Build Coastguard Worker             }
254*a67afe4dSAndroid Build Coastguard Worker             else if (trydelta > delta)
255*a67afe4dSAndroid Build Coastguard Worker             {
256*a67afe4dSAndroid Build Coastguard Worker                delta = trydelta;
257*a67afe4dSAndroid Build Coastguard Worker                ++trydelta;
258*a67afe4dSAndroid Build Coastguard Worker             }
259*a67afe4dSAndroid Build Coastguard Worker             else if (trydelta < delta)
260*a67afe4dSAndroid Build Coastguard Worker             {
261*a67afe4dSAndroid Build Coastguard Worker                delta = trydelta;
262*a67afe4dSAndroid Build Coastguard Worker                --trydelta;
263*a67afe4dSAndroid Build Coastguard Worker             }
264*a67afe4dSAndroid Build Coastguard Worker             else
265*a67afe4dSAndroid Build Coastguard Worker             {
266*a67afe4dSAndroid Build Coastguard Worker                fprintf(stderr, "makesRGB: impossible\n");
267*a67afe4dSAndroid Build Coastguard Worker                exit(1);
268*a67afe4dSAndroid Build Coastguard Worker             }
269*a67afe4dSAndroid Build Coastguard Worker             ecbase = error_count16;
270*a67afe4dSAndroid Build Coastguard Worker          }
271*a67afe4dSAndroid Build Coastguard Worker 
272*a67afe4dSAndroid Build Coastguard Worker          else
273*a67afe4dSAndroid Build Coastguard Worker          {
274*a67afe4dSAndroid Build Coastguard Worker             if (trybase > base)
275*a67afe4dSAndroid Build Coastguard Worker                trybase = base-1;
276*a67afe4dSAndroid Build Coastguard Worker             else if (trybase < base)
277*a67afe4dSAndroid Build Coastguard Worker             {
278*a67afe4dSAndroid Build Coastguard Worker                trybase = base;
279*a67afe4dSAndroid Build Coastguard Worker                ++trydelta;
280*a67afe4dSAndroid Build Coastguard Worker             }
281*a67afe4dSAndroid Build Coastguard Worker             else if (trydelta > delta)
282*a67afe4dSAndroid Build Coastguard Worker                trydelta = delta-1;
283*a67afe4dSAndroid Build Coastguard Worker             else if (trydelta < delta)
284*a67afe4dSAndroid Build Coastguard Worker                break; /* end of tests */
285*a67afe4dSAndroid Build Coastguard Worker          }
286*a67afe4dSAndroid Build Coastguard Worker       }
287*a67afe4dSAndroid Build Coastguard Worker 
288*a67afe4dSAndroid Build Coastguard Worker       png_sRGB_base[ibase >> 7] = base;
289*a67afe4dSAndroid Build Coastguard Worker       png_sRGB_delta[ibase >> 7] = delta;
290*a67afe4dSAndroid Build Coastguard Worker       if (base != ob || delta != od)
291*a67afe4dSAndroid Build Coastguard Worker       {
292*a67afe4dSAndroid Build Coastguard Worker          printf("/* table[%u]={%u,%u} -> {%u,%u} %u -> %u errors */\n",
293*a67afe4dSAndroid Build Coastguard Worker             ibase>>7, ob, od, base, delta, eco, ecbase);
294*a67afe4dSAndroid Build Coastguard Worker       }
295*a67afe4dSAndroid Build Coastguard Worker       else if (0)
296*a67afe4dSAndroid Build Coastguard Worker          printf("/* table[%u]={%u,%u} %u errors */\n", ibase>>7, ob, od,
297*a67afe4dSAndroid Build Coastguard Worker             ecbase);
298*a67afe4dSAndroid Build Coastguard Worker    }
299*a67afe4dSAndroid Build Coastguard Worker 
300*a67afe4dSAndroid Build Coastguard Worker    /* Only do the full (slow) test at the end: */
301*a67afe4dSAndroid Build Coastguard Worker    min_error = -.4999;
302*a67afe4dSAndroid Build Coastguard Worker    max_error = .4999;
303*a67afe4dSAndroid Build Coastguard Worker    error_count = 0;
304*a67afe4dSAndroid Build Coastguard Worker 
305*a67afe4dSAndroid Build Coastguard Worker    for (i=0; i <= max_input; ++i)
306*a67afe4dSAndroid Build Coastguard Worker    {
307*a67afe4dSAndroid Build Coastguard Worker       unsigned int iexact = nearbyint(255*sRGB(i));
308*a67afe4dSAndroid Build Coastguard Worker       unsigned int icalc = PNG_sRGB_FROM_LINEAR(i);
309*a67afe4dSAndroid Build Coastguard Worker 
310*a67afe4dSAndroid Build Coastguard Worker       if (icalc != iexact)
311*a67afe4dSAndroid Build Coastguard Worker       {
312*a67afe4dSAndroid Build Coastguard Worker          double err = 255*sRGB(i) - icalc;
313*a67afe4dSAndroid Build Coastguard Worker 
314*a67afe4dSAndroid Build Coastguard Worker          if (err > (max_error+.001) || err < (min_error-.001))
315*a67afe4dSAndroid Build Coastguard Worker          {
316*a67afe4dSAndroid Build Coastguard Worker             printf(
317*a67afe4dSAndroid Build Coastguard Worker                "/* 0x%08x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n",
318*a67afe4dSAndroid Build Coastguard Worker                i, iexact, icalc, png_sRGB_base[i>>15],
319*a67afe4dSAndroid Build Coastguard Worker                png_sRGB_delta[i>>15], err);
320*a67afe4dSAndroid Build Coastguard Worker          }
321*a67afe4dSAndroid Build Coastguard Worker 
322*a67afe4dSAndroid Build Coastguard Worker          ++error_count;
323*a67afe4dSAndroid Build Coastguard Worker          if (err > max_error)
324*a67afe4dSAndroid Build Coastguard Worker             max_error = err;
325*a67afe4dSAndroid Build Coastguard Worker          else if (err < min_error)
326*a67afe4dSAndroid Build Coastguard Worker             min_error = err;
327*a67afe4dSAndroid Build Coastguard Worker       }
328*a67afe4dSAndroid Build Coastguard Worker    }
329*a67afe4dSAndroid Build Coastguard Worker 
330*a67afe4dSAndroid Build Coastguard Worker    /* Re-check the 16-bit cases too, including the warning if there is an error
331*a67afe4dSAndroid Build Coastguard Worker     * bigger than 1.
332*a67afe4dSAndroid Build Coastguard Worker     */
333*a67afe4dSAndroid Build Coastguard Worker    error_count16 = 0;
334*a67afe4dSAndroid Build Coastguard Worker    max_error16 = 0;
335*a67afe4dSAndroid Build Coastguard Worker    min_error16 = 0;
336*a67afe4dSAndroid Build Coastguard Worker    for (i16=0; i16 <= 65535; ++i16)
337*a67afe4dSAndroid Build Coastguard Worker    {
338*a67afe4dSAndroid Build Coastguard Worker       unsigned int i = 255*i16;
339*a67afe4dSAndroid Build Coastguard Worker       unsigned int iexact = nearbyint(255*sRGB(i));
340*a67afe4dSAndroid Build Coastguard Worker       unsigned int icalc = PNG_sRGB_FROM_LINEAR(i);
341*a67afe4dSAndroid Build Coastguard Worker 
342*a67afe4dSAndroid Build Coastguard Worker       if (icalc != iexact)
343*a67afe4dSAndroid Build Coastguard Worker       {
344*a67afe4dSAndroid Build Coastguard Worker          double err = 255*sRGB(i) - icalc;
345*a67afe4dSAndroid Build Coastguard Worker 
346*a67afe4dSAndroid Build Coastguard Worker          ++error_count16;
347*a67afe4dSAndroid Build Coastguard Worker          if (err > max_error16)
348*a67afe4dSAndroid Build Coastguard Worker             max_error16 = err;
349*a67afe4dSAndroid Build Coastguard Worker          else if (err < min_error16)
350*a67afe4dSAndroid Build Coastguard Worker             min_error16 = err;
351*a67afe4dSAndroid Build Coastguard Worker 
352*a67afe4dSAndroid Build Coastguard Worker          if (abs(icalc - iexact) > 1)
353*a67afe4dSAndroid Build Coastguard Worker             printf(
354*a67afe4dSAndroid Build Coastguard Worker                "/* 0x%04x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n",
355*a67afe4dSAndroid Build Coastguard Worker                i16, iexact, icalc, png_sRGB_base[i>>15],
356*a67afe4dSAndroid Build Coastguard Worker                png_sRGB_delta[i>>15], err);
357*a67afe4dSAndroid Build Coastguard Worker       }
358*a67afe4dSAndroid Build Coastguard Worker    }
359*a67afe4dSAndroid Build Coastguard Worker 
360*a67afe4dSAndroid Build Coastguard Worker    /* Check the round trip for each 8-bit sRGB value. */
361*a67afe4dSAndroid Build Coastguard Worker    for (i16=0; i16 <= 255; ++i16)
362*a67afe4dSAndroid Build Coastguard Worker    {
363*a67afe4dSAndroid Build Coastguard Worker       unsigned int i = 255 * png_sRGB_table[i16];
364*a67afe4dSAndroid Build Coastguard Worker       unsigned int iexact = nearbyint(255*sRGB(i));
365*a67afe4dSAndroid Build Coastguard Worker       unsigned int icalc = PNG_sRGB_FROM_LINEAR(i);
366*a67afe4dSAndroid Build Coastguard Worker 
367*a67afe4dSAndroid Build Coastguard Worker       if (i16 != iexact)
368*a67afe4dSAndroid Build Coastguard Worker       {
369*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "8-bit rounding error: %d -> %d\n", i16, iexact);
370*a67afe4dSAndroid Build Coastguard Worker          exit(1);
371*a67afe4dSAndroid Build Coastguard Worker       }
372*a67afe4dSAndroid Build Coastguard Worker 
373*a67afe4dSAndroid Build Coastguard Worker       if (icalc != i16)
374*a67afe4dSAndroid Build Coastguard Worker       {
375*a67afe4dSAndroid Build Coastguard Worker          double finv = finvsRGB(i16);
376*a67afe4dSAndroid Build Coastguard Worker 
377*a67afe4dSAndroid Build Coastguard Worker          printf("/* 8-bit roundtrip error: %d -> %f -> %d(%f) */\n",
378*a67afe4dSAndroid Build Coastguard Worker             i16, finv, icalc, fsRGB(255*finv));
379*a67afe4dSAndroid Build Coastguard Worker       }
380*a67afe4dSAndroid Build Coastguard Worker    }
381*a67afe4dSAndroid Build Coastguard Worker 
382*a67afe4dSAndroid Build Coastguard Worker 
383*a67afe4dSAndroid Build Coastguard Worker    printf("/* error: %g - %g, %u (%g%%) of readings inexact */\n",
384*a67afe4dSAndroid Build Coastguard Worker       min_error, max_error, error_count, (100.*error_count)/max_input);
385*a67afe4dSAndroid Build Coastguard Worker    printf("/* 16-bit error: %g - %g, %u (%g%%) of readings inexact */\n",
386*a67afe4dSAndroid Build Coastguard Worker       min_error16, max_error16, error_count16, (100.*error_count16)/65535);
387*a67afe4dSAndroid Build Coastguard Worker 
388*a67afe4dSAndroid Build Coastguard Worker    if (!test_only)
389*a67afe4dSAndroid Build Coastguard Worker    {
390*a67afe4dSAndroid Build Coastguard Worker       printf("const png_uint_16 png_sRGB_table[256] =\n{\n   ");
391*a67afe4dSAndroid Build Coastguard Worker       for (i=0; i<255; )
392*a67afe4dSAndroid Build Coastguard Worker       {
393*a67afe4dSAndroid Build Coastguard Worker          do
394*a67afe4dSAndroid Build Coastguard Worker          {
395*a67afe4dSAndroid Build Coastguard Worker             printf("%d,", png_sRGB_table[i++]);
396*a67afe4dSAndroid Build Coastguard Worker          }
397*a67afe4dSAndroid Build Coastguard Worker          while ((i & 0x7) != 0 && i<255);
398*a67afe4dSAndroid Build Coastguard Worker          if (i<255) printf("\n   ");
399*a67afe4dSAndroid Build Coastguard Worker       }
400*a67afe4dSAndroid Build Coastguard Worker       printf("%d\n};\n\n", png_sRGB_table[i]);
401*a67afe4dSAndroid Build Coastguard Worker 
402*a67afe4dSAndroid Build Coastguard Worker 
403*a67afe4dSAndroid Build Coastguard Worker       printf("const png_uint_16 png_sRGB_base[512] =\n{\n   ");
404*a67afe4dSAndroid Build Coastguard Worker       for (i=0; i<511; )
405*a67afe4dSAndroid Build Coastguard Worker       {
406*a67afe4dSAndroid Build Coastguard Worker          do
407*a67afe4dSAndroid Build Coastguard Worker          {
408*a67afe4dSAndroid Build Coastguard Worker             printf("%d,", png_sRGB_base[i++]);
409*a67afe4dSAndroid Build Coastguard Worker          }
410*a67afe4dSAndroid Build Coastguard Worker          while ((i & 0x7) != 0 && i<511);
411*a67afe4dSAndroid Build Coastguard Worker          if (i<511) printf("\n   ");
412*a67afe4dSAndroid Build Coastguard Worker       }
413*a67afe4dSAndroid Build Coastguard Worker       printf("%d\n};\n\n", png_sRGB_base[i]);
414*a67afe4dSAndroid Build Coastguard Worker 
415*a67afe4dSAndroid Build Coastguard Worker       printf("const png_byte png_sRGB_delta[512] =\n{\n   ");
416*a67afe4dSAndroid Build Coastguard Worker       for (i=0; i<511; )
417*a67afe4dSAndroid Build Coastguard Worker       {
418*a67afe4dSAndroid Build Coastguard Worker          do
419*a67afe4dSAndroid Build Coastguard Worker          {
420*a67afe4dSAndroid Build Coastguard Worker             printf("%d,", png_sRGB_delta[i++]);
421*a67afe4dSAndroid Build Coastguard Worker          }
422*a67afe4dSAndroid Build Coastguard Worker          while ((i & 0xf) != 0 && i<511);
423*a67afe4dSAndroid Build Coastguard Worker          if (i<511) printf("\n   ");
424*a67afe4dSAndroid Build Coastguard Worker       }
425*a67afe4dSAndroid Build Coastguard Worker       printf("%d\n};\n\n", png_sRGB_delta[i]);
426*a67afe4dSAndroid Build Coastguard Worker    }
427*a67afe4dSAndroid Build Coastguard Worker 
428*a67afe4dSAndroid Build Coastguard Worker    return 0;
429*a67afe4dSAndroid Build Coastguard Worker }
430