1 /* makesRGB.c -- build sRGB-to-linear and linear-to-sRGB conversion tables
3 * Last changed in libpng 1.6.0 [February 14, 2013]
5 * COPYRIGHT: Written by John Cunningham Bowler, 2013.
6 * To the extent possible under law, the author has waived all copyright and
7 * related or neighboring rights to this work. This work is published from:
10 * Make a table to convert 8-bit sRGB encoding values into the closest 16-bit
13 * Make two tables to take a linear value scaled to 255*65535 and return an
14 * approximation to the 8-bit sRGB encoded value. Calculate the error in these
15 * tables and display it.
22 /* pngpriv.h includes the definition of 'PNG_sRGB_FROM_LINEAR' which is required
23 * to verify the actual code.
25 #include "../../pngpriv.h"
29 /* The tables are declared 'const' in pngpriv.h, so this redefines the tables to
32 #define png_sRGB_table sRGB_table
33 #define png_sRGB_base sRGB_base
34 #define png_sRGB_delta sRGB_delta
36 static png_uint_16 png_sRGB_table
[256];
37 static png_uint_16 png_sRGB_base
[512];
38 static png_byte png_sRGB_delta
[512];
40 static const unsigned int max_input
= 255*65535;
45 return sRGB_from_linear(l
/max_input
);
55 finvsRGB(unsigned int i
)
57 return 65535 * linear_from_sRGB(i
/255.);
61 invsRGB(unsigned int i
)
63 unsigned int x
= nearbyint(finvsRGB(i
));
67 fprintf(stderr
, "invsRGB(%u) overflows to %u\n", i
, x
);
71 return (png_uint_16
)x
;
75 main(int argc
, char **argv
)
77 unsigned int i
, i16
, ibase
;
80 double min_error16
= 0;
81 double max_error16
= 0;
83 double adjust_lo
= 0.4, adjust_hi
= 0.6, adjust_mid
= 0.5;
84 unsigned int ec_lo
= 0, ec_hi
= 0, ec_mid
= 0;
85 unsigned int error_count
= 0;
86 unsigned int error_count16
= 0;
90 test_only
= strcmp("--test", argv
[1]) == 0;
92 /* Initialize the encoding table first. */
95 png_sRGB_table
[i
] = invsRGB(i
);
98 /* Now work out the decoding tables (this is where the error comes in because
99 * there are 512 set points and 512 straight lines between them.)
109 else if (ec_mid
== 0)
112 else if (ec_mid
< ec_hi
)
113 adjust
= (adjust_mid
+ adjust_hi
)/2;
115 else if (ec_mid
< ec_lo
)
116 adjust
= (adjust_mid
+ adjust_lo
)/2;
120 fprintf(stderr
, "not reached: %u .. %u .. %u\n", ec_lo
, ec_mid
, ec_hi
);
124 /* Calculate the table using the current 'adjust' */
125 for (i
=0; i
<=511; ++i
)
127 double lo
= 255 * sRGB(i
<< 15);
128 double hi
= 255 * sRGB((i
+1) << 15);
131 calc
= nearbyint((lo
+adjust
) * 256);
134 fprintf(stderr
, "table[%d][0]: overflow %08x (%d)\n", i
, calc
,
138 png_sRGB_base
[i
] = calc
;
140 calc
= nearbyint((hi
-lo
) * 32);
143 fprintf(stderr
, "table[%d][1]: overflow %08x (%d)\n", i
, calc
,
147 png_sRGB_delta
[i
] = calc
;
150 /* Check the 16-bit linear values alone: */
152 for (i16
=0; i16
<= 65535; ++i16
)
154 unsigned int i
= 255*i16
;
155 unsigned int iexact
= nearbyint(255*sRGB(i
));
156 unsigned int icalc
= PNG_sRGB_FROM_LINEAR(i
);
162 /* Now try changing the adjustment. */
164 ec_lo
= error_count16
;
167 ec_hi
= error_count16
;
169 else if (ec_mid
== 0)
171 ec_mid
= error_count16
;
172 printf("/* initial error counts: %u .. %u .. %u */\n", ec_lo
, ec_mid
,
176 else if (error_count16
< ec_mid
)
178 printf("/* adjust (mid ): %f: %u -> %u */\n", adjust
, ec_mid
,
180 ec_mid
= error_count16
;
184 else if (adjust
< adjust_mid
&& error_count16
< ec_lo
)
186 printf("/* adjust (low ): %f: %u -> %u */\n", adjust
, ec_lo
,
188 ec_lo
= error_count16
;
192 else if (adjust
> adjust_mid
&& error_count16
< ec_hi
)
194 printf("/* adjust (high): %f: %u -> %u */\n", adjust
, ec_hi
,
196 ec_hi
= error_count16
;
203 printf("/* adjust: %f: %u */\n", adjust
, ec_mid
);
208 /* For each entry in the table try to adjust it to minimize the error count
209 * in that entry. Each entry corresponds to 128 input values.
211 for (ibase
=0; ibase
<65536; ibase
+=128)
213 png_uint_16 base
= png_sRGB_base
[ibase
>> 7], trybase
= base
, ob
=base
;
214 png_byte delta
= png_sRGB_delta
[ibase
>> 7], trydelta
= delta
, od
=delta
;
215 unsigned int ecbase
= 0, eco
;
219 png_sRGB_base
[ibase
>> 7] = trybase
;
220 png_sRGB_delta
[ibase
>> 7] = trydelta
;
222 /* Check the 16-bit linear values alone: */
224 for (i16
=ibase
; i16
< ibase
+128; ++i16
)
226 unsigned int i
= 255*i16
;
227 unsigned int iexact
= nearbyint(255*sRGB(i
));
228 unsigned int icalc
= PNG_sRGB_FROM_LINEAR(i
);
234 if (error_count16
== 0)
239 eco
= ecbase
= error_count16
;
240 ++trybase
; /* First test */
243 else if (error_count16
< ecbase
)
250 else if (trybase
< base
)
255 else if (trydelta
> delta
)
260 else if (trydelta
< delta
)
267 fprintf(stderr
, "makesRGB: impossible\n");
270 ecbase
= error_count16
;
277 else if (trybase
< base
)
282 else if (trydelta
> delta
)
284 else if (trydelta
< delta
)
285 break; /* end of tests */
289 png_sRGB_base
[ibase
>> 7] = base
;
290 png_sRGB_delta
[ibase
>> 7] = delta
;
291 if (base
!= ob
|| delta
!= od
)
293 printf("/* table[%u]={%u,%u} -> {%u,%u} %u -> %u errors */\n",
294 ibase
>>7, ob
, od
, base
, delta
, eco
, ecbase
);
297 printf("/* table[%u]={%u,%u} %u errors */\n", ibase
>>7, ob
, od
,
301 /* Only do the full (slow) test at the end: */
306 for (i
=0; i
<= max_input
; ++i
)
308 unsigned int iexact
= nearbyint(255*sRGB(i
));
309 unsigned int icalc
= PNG_sRGB_FROM_LINEAR(i
);
313 double err
= 255*sRGB(i
) - icalc
;
315 if (err
> (max_error
+.001) || err
< (min_error
-.001))
318 "/* 0x%08x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n",
319 i
, iexact
, icalc
, png_sRGB_base
[i
>>15],
320 png_sRGB_delta
[i
>>15], err
);
326 else if (err
< min_error
)
331 /* Re-check the 16-bit cases too, including the warning if there is an error
337 for (i16
=0; i16
<= 65535; ++i16
)
339 unsigned int i
= 255*i16
;
340 unsigned int iexact
= nearbyint(255*sRGB(i
));
341 unsigned int icalc
= PNG_sRGB_FROM_LINEAR(i
);
345 double err
= 255*sRGB(i
) - icalc
;
348 if (err
> max_error16
)
350 else if (err
< min_error16
)
353 if (abs(icalc
- iexact
) > 1)
355 "/* 0x%04x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n",
356 i16
, iexact
, icalc
, png_sRGB_base
[i
>>15],
357 png_sRGB_delta
[i
>>15], err
);
361 /* Check the round trip for each 8-bit sRGB value. */
362 for (i16
=0; i16
<= 255; ++i16
)
364 unsigned int i
= 255 * png_sRGB_table
[i16
];
365 unsigned int iexact
= nearbyint(255*sRGB(i
));
366 unsigned int icalc
= PNG_sRGB_FROM_LINEAR(i
);
370 fprintf(stderr
, "8-bit rounding error: %d -> %d\n", i16
, iexact
);
376 double finv
= finvsRGB(i16
);
378 printf("/* 8-bit roundtrip error: %d -> %f -> %d(%f) */\n",
379 i16
, finv
, icalc
, fsRGB(255*finv
));
384 printf("/* error: %g - %g, %u (%g%%) of readings inexact */\n",
385 min_error
, max_error
, error_count
, (100.*error_count
)/max_input
);
386 printf("/* 16-bit error: %g - %g, %u (%g%%) of readings inexact */\n",
387 min_error16
, max_error16
, error_count16
, (100.*error_count16
)/65535);
391 printf("PNG_CONST png_uint_16 png_sRGB_table[256] =\n{\n ");
396 printf("%d,", png_sRGB_table
[i
++]);
398 while ((i
& 0x7) != 0 && i
<255);
399 if (i
<255) printf("\n ");
401 printf("%d\n};\n\n", png_sRGB_table
[i
]);
404 printf("PNG_CONST png_uint_16 png_sRGB_base[512] =\n{\n ");
409 printf("%d,", png_sRGB_base
[i
++]);
411 while ((i
& 0x7) != 0 && i
<511);
412 if (i
<511) printf("\n ");
414 printf("%d\n};\n\n", png_sRGB_base
[i
]);
416 printf("PNG_CONST png_byte png_sRGB_delta[512] =\n{\n ");
421 printf("%d,", png_sRGB_delta
[i
++]);
423 while ((i
& 0xf) != 0 && i
<511);
424 if (i
<511) printf("\n ");
426 printf("%d\n};\n\n", png_sRGB_delta
[i
]);