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