Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / libs / png / contrib / libtests / pngstest.c
blob35e7c8779a2763119e7a8428bc3f7033e9017952
1 /*-
2 * pngstest.c
4 * Copyright (c) 2013 John Cunningham Bowler
6 * Last changed in libpng 1.6.1 [March 28, 2013]
8 * This code is released under the libpng license.
9 * For conditions of distribution and use, see the disclaimer
10 * and license in png.h
12 * Test for the PNG 'simplified' APIs.
14 #define _ISOC90_SOURCE 1
15 #define MALLOC_CHECK_ 2/*glibc facility: turn on debugging*/
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #include <math.h>
25 #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
26 # include <config.h>
27 #endif
29 /* Define the following to use this test against your installed libpng, rather
30 * than the one being built here:
32 #ifdef PNG_FREESTANDING_TESTS
33 # include <png.h>
34 #else
35 # include "../../png.h"
36 #endif
38 #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* Else nothing can be done */
39 #include "../tools/sRGB.h"
41 /* KNOWN ISSUES
43 * These defines switch on alternate algorithms for format conversions to match
44 * the current libpng implementation; they are set to allow pngstest to pass
45 * even though libpng is producing answers that are not as correct as they
46 * should be.
48 #define ALLOW_UNUSED_GPC 0
49 /* If true include unused static GPC functions and declare an external array
50 * of them to hide the fact that they are unused. This is for development
51 * use while testing the correct function to use to take into account libpng
52 * misbehavior, such as using a simple power law to correct sRGB to linear.
55 /* The following is to support direct compilation of this file as C++ */
56 #ifdef __cplusplus
57 # define voidcast(type, value) static_cast<type>(value)
58 # define aligncastconst(type, value) \
59 static_cast<type>(static_cast<const void*>(value))
60 #else
61 # define voidcast(type, value) (value)
62 # define aligncastconst(type, value) ((const void*)(value))
63 #endif /* __cplusplus */
65 /* During parallel runs of pngstest each temporary file needs a unique name,
66 * this is used to permit uniqueness using a command line argument which can be
67 * up to 22 characters long.
69 static char tmpf[23] = "TMP";
71 /* Generate random bytes. This uses a boring repeatable algorithm and it
72 * is implemented here so that it gives the same set of numbers on every
73 * architecture. It's a linear congruential generator (Knuth or Sedgewick
74 * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and
75 * Hill, "The Art of Electronics".
77 static void
78 make_random_bytes(png_uint_32* seed, void* pv, size_t size)
80 png_uint_32 u0 = seed[0], u1 = seed[1];
81 png_bytep bytes = voidcast(png_bytep, pv);
83 /* There are thirty three bits, the next bit in the sequence is bit-33 XOR
84 * bit-20. The top 1 bit is in u1, the bottom 32 are in u0.
86 size_t i;
87 for (i=0; i<size; ++i)
89 /* First generate 8 new bits then shift them in at the end. */
90 png_uint_32 u = ((u0 >> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff;
91 u1 <<= 8;
92 u1 |= u0 >> 24;
93 u0 <<= 8;
94 u0 |= u;
95 *bytes++ = (png_byte)u;
98 seed[0] = u0;
99 seed[1] = u1;
102 static void
103 random_color(png_colorp color)
105 static png_uint_32 color_seed[2] = { 0x12345678, 0x9abcdef };
106 make_random_bytes(color_seed, color, sizeof *color);
109 /* Math support - neither Cygwin nor Visual Studio have C99 support and we need
110 * a predictable rounding function, so make one here:
112 static double
113 closestinteger(double x)
115 return floor(x + .5);
118 /* Cast support: remove GCC whines. */
119 static png_byte
120 u8d(double d)
122 d = closestinteger(d);
123 return (png_byte)d;
126 static png_uint_16
127 u16d(double d)
129 d = closestinteger(d);
130 return (png_uint_16)d;
133 /* sRGB support: use exact calculations rounded to the nearest int, see the
134 * fesetround() call in main(). sRGB_to_d optimizes the 8 to 16-bit conversion.
136 static double sRGB_to_d[256];
137 static double g22_to_d[256];
139 static void
140 init_sRGB_to_d(void)
142 int i;
144 sRGB_to_d[0] = 0;
145 for (i=1; i<255; ++i)
146 sRGB_to_d[i] = linear_from_sRGB(i/255.);
147 sRGB_to_d[255] = 1;
149 g22_to_d[0] = 0;
150 for (i=1; i<255; ++i)
151 g22_to_d[i] = pow(i/255., 1/.45455);
152 g22_to_d[255] = 1;
155 static png_byte
156 sRGB(double linear /*range 0.0 .. 1.0*/)
158 return u8d(255 * sRGB_from_linear(linear));
161 static png_byte
162 isRGB(int fixed_linear)
164 return sRGB(fixed_linear / 65535.);
167 #if 0 /* not used */
168 static png_byte
169 unpremultiply(int component, int alpha)
171 if (alpha <= component)
172 return 255; /* Arbitrary, but consistent with the libpng code */
174 else if (alpha >= 65535)
175 return isRGB(component);
177 else
178 return sRGB((double)component / alpha);
180 #endif
182 static png_uint_16
183 ilinear(int fixed_srgb)
185 return u16d(65535 * sRGB_to_d[fixed_srgb]);
188 static png_uint_16
189 ilineara(int fixed_srgb, int alpha)
191 return u16d((257 * alpha) * sRGB_to_d[fixed_srgb]);
194 static png_uint_16
195 ilinear_g22(int fixed_srgb)
197 return u16d(65535 * g22_to_d[fixed_srgb]);
200 #if ALLOW_UNUSED_GPC
201 static png_uint_16
202 ilineara_g22(int fixed_srgb, int alpha)
204 return u16d((257 * alpha) * g22_to_d[fixed_srgb]);
206 #endif
208 static double
209 YfromRGBint(int ir, int ig, int ib)
211 double r = ir;
212 double g = ig;
213 double b = ib;
214 return YfromRGB(r, g, b);
217 #if 0 /* unused */
218 /* The error that results from using a 2.2 power law in place of the correct
219 * sRGB transform, given an 8-bit value which might be either sRGB or power-law.
221 static int
222 power_law_error8(int value)
224 if (value > 0 && value < 255)
226 double vd = value / 255.;
227 double e = fabs(
228 pow(sRGB_to_d[value], 1/2.2) - sRGB_from_linear(pow(vd, 2.2)));
230 /* Always allow an extra 1 here for rounding errors */
231 e = 1+floor(255 * e);
232 return (int)e;
235 return 0;
238 static int error_in_sRGB_roundtrip = 56; /* by experiment */
239 static int
240 power_law_error16(int value)
242 if (value > 0 && value < 65535)
244 /* Round trip the value through an 8-bit representation but using
245 * non-matching to/from conversions.
247 double vd = value / 65535.;
248 double e = fabs(
249 pow(sRGB_from_linear(vd), 2.2) - linear_from_sRGB(pow(vd, 1/2.2)));
251 /* Always allow an extra 1 here for rounding errors */
252 e = error_in_sRGB_roundtrip+floor(65535 * e);
253 return (int)e;
256 return 0;
259 static int
260 compare_8bit(int v1, int v2, int error_limit, int multiple_algorithms)
262 int e = abs(v1-v2);
263 int ev1, ev2;
265 if (e <= error_limit)
266 return 1;
268 if (!multiple_algorithms)
269 return 0;
271 ev1 = power_law_error8(v1);
272 if (e <= ev1)
273 return 1;
275 ev2 = power_law_error8(v2);
276 if (e <= ev2)
277 return 1;
279 return 0;
282 static int
283 compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms)
285 int e = abs(v1-v2);
286 int ev1, ev2;
288 if (e <= error_limit)
289 return 1;
291 /* "multiple_algorithms" in this case means that a color-map has been
292 * involved somewhere, so we can deduce that the values were forced to 8-bit
293 * (like the via_linear case for 8-bit.)
295 if (!multiple_algorithms)
296 return 0;
298 ev1 = power_law_error16(v1);
299 if (e <= ev1)
300 return 1;
302 ev2 = power_law_error16(v2);
303 if (e <= ev2)
304 return 1;
306 return 0;
308 #endif /* unused */
310 #define READ_FILE 1 /* else memory */
311 #define USE_STDIO 2 /* else use file name */
312 #define STRICT 4 /* fail on warnings too */
313 #define VERBOSE 8
314 #define KEEP_TMPFILES 16 /* else delete temporary files */
315 #define KEEP_GOING 32
316 #define ACCUMULATE 64
317 #define FAST_WRITE 128
318 #define sRGB_16BIT 256
320 static void
321 print_opts(png_uint_32 opts)
323 if (opts & READ_FILE)
324 printf(" --file");
325 if (opts & USE_STDIO)
326 printf(" --stdio");
327 if (opts & STRICT)
328 printf(" --strict");
329 if (opts & VERBOSE)
330 printf(" --verbose");
331 if (opts & KEEP_TMPFILES)
332 printf(" --preserve");
333 if (opts & KEEP_GOING)
334 printf(" --keep-going");
335 if (opts & ACCUMULATE)
336 printf(" --accumulate");
337 if (!(opts & FAST_WRITE)) /* --fast is currently the default */
338 printf(" --slow");
339 if (opts & sRGB_16BIT)
340 printf(" --sRGB-16bit");
343 #define FORMAT_NO_CHANGE 0x80000000 /* additional flag */
345 /* A name table for all the formats - defines the format of the '+' arguments to
346 * pngstest.
348 #define FORMAT_COUNT 64
349 #define FORMAT_MASK 0x3f
350 static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] =
352 "sRGB-gray",
353 "sRGB-gray+alpha",
354 "sRGB-rgb",
355 "sRGB-rgb+alpha",
356 "linear-gray",
357 "linear-gray+alpha",
358 "linear-rgb",
359 "linear-rgb+alpha",
361 "color-mapped-sRGB-gray",
362 "color-mapped-sRGB-gray+alpha",
363 "color-mapped-sRGB-rgb",
364 "color-mapped-sRGB-rgb+alpha",
365 "color-mapped-linear-gray",
366 "color-mapped-linear-gray+alpha",
367 "color-mapped-linear-rgb",
368 "color-mapped-linear-rgb+alpha",
370 "sRGB-gray",
371 "sRGB-gray+alpha",
372 "sRGB-bgr",
373 "sRGB-bgr+alpha",
374 "linear-gray",
375 "linear-gray+alpha",
376 "linear-bgr",
377 "linear-bgr+alpha",
379 "color-mapped-sRGB-gray",
380 "color-mapped-sRGB-gray+alpha",
381 "color-mapped-sRGB-bgr",
382 "color-mapped-sRGB-bgr+alpha",
383 "color-mapped-linear-gray",
384 "color-mapped-linear-gray+alpha",
385 "color-mapped-linear-bgr",
386 "color-mapped-linear-bgr+alpha",
388 "sRGB-gray",
389 "alpha+sRGB-gray",
390 "sRGB-rgb",
391 "alpha+sRGB-rgb",
392 "linear-gray",
393 "alpha+linear-gray",
394 "linear-rgb",
395 "alpha+linear-rgb",
397 "color-mapped-sRGB-gray",
398 "color-mapped-alpha+sRGB-gray",
399 "color-mapped-sRGB-rgb",
400 "color-mapped-alpha+sRGB-rgb",
401 "color-mapped-linear-gray",
402 "color-mapped-alpha+linear-gray",
403 "color-mapped-linear-rgb",
404 "color-mapped-alpha+linear-rgb",
406 "sRGB-gray",
407 "alpha+sRGB-gray",
408 "sRGB-bgr",
409 "alpha+sRGB-bgr",
410 "linear-gray",
411 "alpha+linear-gray",
412 "linear-bgr",
413 "alpha+linear-bgr",
415 "color-mapped-sRGB-gray",
416 "color-mapped-alpha+sRGB-gray",
417 "color-mapped-sRGB-bgr",
418 "color-mapped-alpha+sRGB-bgr",
419 "color-mapped-linear-gray",
420 "color-mapped-alpha+linear-gray",
421 "color-mapped-linear-bgr",
422 "color-mapped-alpha+linear-bgr",
425 /* Decode an argument to a format number. */
426 static png_uint_32
427 formatof(const char *arg)
429 char *ep;
430 unsigned long format = strtoul(arg, &ep, 0);
432 if (ep > arg && *ep == 0 && format < FORMAT_COUNT)
433 return (png_uint_32)format;
435 else for (format=0; format < FORMAT_COUNT; ++format)
437 if (strcmp(format_names[format], arg) == 0)
438 return (png_uint_32)format;
441 fprintf(stderr, "pngstest: format name '%s' invalid\n", arg);
442 return FORMAT_COUNT;
445 /* Bitset/test functions for formats */
446 #define FORMAT_SET_COUNT (FORMAT_COUNT / 32)
447 typedef struct
449 png_uint_32 bits[FORMAT_SET_COUNT];
451 format_list;
453 static void format_init(format_list *pf)
455 int i;
456 for (i=0; i<FORMAT_SET_COUNT; ++i)
457 pf->bits[i] = 0; /* All off */
460 #if 0 /* currently unused */
461 static void format_clear(format_list *pf)
463 int i;
464 for (i=0; i<FORMAT_SET_COUNT; ++i)
465 pf->bits[i] = 0;
467 #endif
469 static int format_is_initial(format_list *pf)
471 int i;
472 for (i=0; i<FORMAT_SET_COUNT; ++i)
473 if (pf->bits[i] != 0)
474 return 0;
476 return 1;
479 static int format_set(format_list *pf, png_uint_32 format)
481 if (format < FORMAT_COUNT)
482 return pf->bits[format >> 5] |= ((png_uint_32)1) << (format & 31);
484 return 0;
487 #if 0 /* currently unused */
488 static int format_unset(format_list *pf, png_uint_32 format)
490 if (format < FORMAT_COUNT)
491 return pf->bits[format >> 5] &= ~((png_uint_32)1) << (format & 31);
493 return 0;
495 #endif
497 static int format_isset(format_list *pf, png_uint_32 format)
499 return format < FORMAT_COUNT &&
500 (pf->bits[format >> 5] & (((png_uint_32)1) << (format & 31))) != 0;
503 static void format_default(format_list *pf, int redundant)
505 if (redundant)
507 int i;
509 /* set everything, including flags that are pointless */
510 for (i=0; i<FORMAT_SET_COUNT; ++i)
511 pf->bits[i] = ~(png_uint_32)0;
514 else
516 png_uint_32 f;
518 for (f=0; f<FORMAT_COUNT; ++f)
520 /* Eliminate redundant settings. */
521 /* BGR is meaningless if no color: */
522 if ((f & PNG_FORMAT_FLAG_COLOR) == 0 && (f & PNG_FORMAT_FLAG_BGR) != 0)
523 continue;
525 /* AFIRST is meaningless if no alpha: */
526 if ((f & PNG_FORMAT_FLAG_ALPHA) == 0 &&
527 (f & PNG_FORMAT_FLAG_AFIRST) != 0)
528 continue;
530 format_set(pf, f);
535 /* THE Image STRUCTURE */
536 /* The super-class of a png_image, contains the decoded image plus the input
537 * data necessary to re-read the file with a different format.
539 typedef struct
541 png_image image;
542 png_uint_32 opts;
543 const char *file_name;
544 int stride_extra;
545 FILE *input_file;
546 png_voidp input_memory;
547 png_size_t input_memory_size;
548 png_bytep buffer;
549 ptrdiff_t stride;
550 png_size_t bufsize;
551 png_size_t allocsize;
552 char tmpfile_name[32];
553 png_uint_16 colormap[256*4];
555 Image;
557 /* Initializer: also sets the permitted error limit for 16-bit operations. */
558 static void
559 newimage(Image *image)
561 memset(image, 0, sizeof *image);
564 /* Reset the image to be read again - only needs to rewind the FILE* at present.
566 static void
567 resetimage(Image *image)
569 if (image->input_file != NULL)
570 rewind(image->input_file);
573 /* Free the image buffer; the buffer is re-used on a re-read, this is just for
574 * cleanup.
576 static void
577 freebuffer(Image *image)
579 if (image->buffer) free(image->buffer);
580 image->buffer = NULL;
581 image->bufsize = 0;
582 image->allocsize = 0;
585 /* Delete function; cleans out all the allocated data and the temporary file in
586 * the image.
588 static void
589 freeimage(Image *image)
591 freebuffer(image);
592 png_image_free(&image->image);
594 if (image->input_file != NULL)
596 fclose(image->input_file);
597 image->input_file = NULL;
600 if (image->input_memory != NULL)
602 free(image->input_memory);
603 image->input_memory = NULL;
604 image->input_memory_size = 0;
607 if (image->tmpfile_name[0] != 0 && (image->opts & KEEP_TMPFILES) == 0)
609 remove(image->tmpfile_name);
610 image->tmpfile_name[0] = 0;
614 /* This is actually a re-initializer; allows an image structure to be re-used by
615 * freeing everything that relates to an old image.
617 static void initimage(Image *image, png_uint_32 opts, const char *file_name,
618 int stride_extra)
620 freeimage(image);
621 memset(&image->image, 0, sizeof image->image);
622 image->opts = opts;
623 image->file_name = file_name;
624 image->stride_extra = stride_extra;
627 /* Make sure the image buffer is big enough; allows re-use of the buffer if the
628 * image is re-read.
630 #define BUFFER_INIT8 73
631 static void
632 allocbuffer(Image *image)
634 png_size_t size = PNG_IMAGE_BUFFER_SIZE(image->image, image->stride);
636 if (size+32 > image->bufsize)
638 freebuffer(image);
639 image->buffer = voidcast(png_bytep, malloc(size+32));
640 if (image->buffer == NULL)
642 fflush(stdout);
643 fprintf(stderr,
644 "simpletest: out of memory allocating %lu(+32) byte buffer\n",
645 (unsigned long)size);
646 exit(1);
648 image->bufsize = size+32;
651 memset(image->buffer, 95, image->bufsize);
652 memset(image->buffer+16, BUFFER_INIT8, size);
653 image->allocsize = size;
656 /* Make sure 16 bytes match the given byte. */
657 static int
658 check16(png_const_bytep bp, int b)
660 int i = 16;
663 if (*bp != b) return 1;
664 while (--i);
666 return 0;
669 /* Check for overwrite in the image buffer. */
670 static void
671 checkbuffer(Image *image, const char *arg)
673 if (check16(image->buffer, 95))
675 fflush(stdout);
676 fprintf(stderr, "%s: overwrite at start of image buffer\n", arg);
677 exit(1);
680 if (check16(image->buffer+16+image->allocsize, 95))
682 fflush(stdout);
683 fprintf(stderr, "%s: overwrite at end of image buffer\n", arg);
684 exit(1);
688 /* ERROR HANDLING */
689 /* Log a terminal error, also frees the libpng part of the image if necessary.
691 static int
692 logerror(Image *image, const char *a1, const char *a2, const char *a3)
694 fflush(stdout);
695 if (image->image.warning_or_error)
696 fprintf(stderr, "%s%s%s: %s\n", a1, a2, a3, image->image.message);
698 else
699 fprintf(stderr, "%s%s%s\n", a1, a2, a3);
701 if (image->image.opaque != NULL)
703 fprintf(stderr, "%s: image opaque pointer non-NULL on error\n",
704 image->file_name);
705 png_image_free(&image->image);
708 return 0;
711 /* Log an error and close a file (just a utility to do both things in one
712 * function call.)
714 static int
715 logclose(Image *image, FILE *f, const char *name, const char *operation)
717 int e = errno;
719 fclose(f);
720 return logerror(image, name, operation, strerror(e));
723 /* Make sure the png_image has been freed - validates that libpng is doing what
724 * the spec says and freeing the image.
726 static int
727 checkopaque(Image *image)
729 if (image->image.opaque != NULL)
731 png_image_free(&image->image);
732 return logerror(image, image->file_name, ": opaque not NULL", "");
735 else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0)
736 return logerror(image, image->file_name, " --strict", "");
738 else
739 return 1;
742 /* IMAGE COMPARISON/CHECKING */
743 /* Compare the pixels of two images, which should be the same but aren't. The
744 * images must have been checked for a size match.
746 typedef struct
748 /* The components, for grayscale images the gray value is in 'g' and if alpha
749 * is not present 'a' is set to 255 or 65535 according to format.
751 int r, g, b, a;
752 } Pixel;
754 typedef struct
756 /* The background as the original sRGB 8-bit value converted to the final
757 * integer format and as a double precision linear value in the range 0..1
758 * for with partially transparent pixels.
760 int ir, ig, ib;
761 double dr, dg, db; /* linear r,g,b scaled to 0..1 */
762 } Background;
764 /* Basic image formats; control the data but not the layout thereof. */
765 #define BASE_FORMATS\
766 (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_LINEAR)
768 /* Read a Pixel from a buffer. The code below stores the correct routine for
769 * the format in a function pointer, these are the routines:
771 static void
772 gp_g8(Pixel *p, png_const_voidp pb)
774 png_const_bytep pp = voidcast(png_const_bytep, pb);
776 p->r = p->g = p->b = pp[0];
777 p->a = 255;
780 static void
781 gp_ga8(Pixel *p, png_const_voidp pb)
783 png_const_bytep pp = voidcast(png_const_bytep, pb);
785 p->r = p->g = p->b = pp[0];
786 p->a = pp[1];
789 static void
790 gp_ag8(Pixel *p, png_const_voidp pb)
792 png_const_bytep pp = voidcast(png_const_bytep, pb);
794 p->r = p->g = p->b = pp[1];
795 p->a = pp[0];
798 static void
799 gp_rgb8(Pixel *p, png_const_voidp pb)
801 png_const_bytep pp = voidcast(png_const_bytep, pb);
803 p->r = pp[0];
804 p->g = pp[1];
805 p->b = pp[2];
806 p->a = 255;
809 static void
810 gp_bgr8(Pixel *p, png_const_voidp pb)
812 png_const_bytep pp = voidcast(png_const_bytep, pb);
814 p->r = pp[2];
815 p->g = pp[1];
816 p->b = pp[0];
817 p->a = 255;
820 static void
821 gp_rgba8(Pixel *p, png_const_voidp pb)
823 png_const_bytep pp = voidcast(png_const_bytep, pb);
825 p->r = pp[0];
826 p->g = pp[1];
827 p->b = pp[2];
828 p->a = pp[3];
831 static void
832 gp_bgra8(Pixel *p, png_const_voidp pb)
834 png_const_bytep pp = voidcast(png_const_bytep, pb);
836 p->r = pp[2];
837 p->g = pp[1];
838 p->b = pp[0];
839 p->a = pp[3];
842 static void
843 gp_argb8(Pixel *p, png_const_voidp pb)
845 png_const_bytep pp = voidcast(png_const_bytep, pb);
847 p->r = pp[1];
848 p->g = pp[2];
849 p->b = pp[3];
850 p->a = pp[0];
853 static void
854 gp_abgr8(Pixel *p, png_const_voidp pb)
856 png_const_bytep pp = voidcast(png_const_bytep, pb);
858 p->r = pp[3];
859 p->g = pp[2];
860 p->b = pp[1];
861 p->a = pp[0];
864 static void
865 gp_g16(Pixel *p, png_const_voidp pb)
867 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
869 p->r = p->g = p->b = pp[0];
870 p->a = 65535;
873 static void
874 gp_ga16(Pixel *p, png_const_voidp pb)
876 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
878 p->r = p->g = p->b = pp[0];
879 p->a = pp[1];
882 static void
883 gp_ag16(Pixel *p, png_const_voidp pb)
885 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
887 p->r = p->g = p->b = pp[1];
888 p->a = pp[0];
891 static void
892 gp_rgb16(Pixel *p, png_const_voidp pb)
894 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
896 p->r = pp[0];
897 p->g = pp[1];
898 p->b = pp[2];
899 p->a = 65535;
902 static void
903 gp_bgr16(Pixel *p, png_const_voidp pb)
905 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
907 p->r = pp[2];
908 p->g = pp[1];
909 p->b = pp[0];
910 p->a = 65535;
913 static void
914 gp_rgba16(Pixel *p, png_const_voidp pb)
916 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
918 p->r = pp[0];
919 p->g = pp[1];
920 p->b = pp[2];
921 p->a = pp[3];
924 static void
925 gp_bgra16(Pixel *p, png_const_voidp pb)
927 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
929 p->r = pp[2];
930 p->g = pp[1];
931 p->b = pp[0];
932 p->a = pp[3];
935 static void
936 gp_argb16(Pixel *p, png_const_voidp pb)
938 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
940 p->r = pp[1];
941 p->g = pp[2];
942 p->b = pp[3];
943 p->a = pp[0];
946 static void
947 gp_abgr16(Pixel *p, png_const_voidp pb)
949 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb);
951 p->r = pp[3];
952 p->g = pp[2];
953 p->b = pp[1];
954 p->a = pp[0];
957 /* Given a format, return the correct one of the above functions. */
958 static void (*
959 get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb)
961 /* The color-map flag is irrelevant here - the caller of the function
962 * returned must either pass the buffer or, for a color-mapped image, the
963 * correct entry in the color-map.
965 if (format & PNG_FORMAT_FLAG_LINEAR)
967 if (format & PNG_FORMAT_FLAG_COLOR)
969 if (format & PNG_FORMAT_FLAG_BGR)
971 if (format & PNG_FORMAT_FLAG_ALPHA)
973 if (format & PNG_FORMAT_FLAG_AFIRST)
974 return gp_abgr16;
976 else
977 return gp_bgra16;
980 else
981 return gp_bgr16;
984 else
986 if (format & PNG_FORMAT_FLAG_ALPHA)
988 if (format & PNG_FORMAT_FLAG_AFIRST)
989 return gp_argb16;
991 else
992 return gp_rgba16;
995 else
996 return gp_rgb16;
1000 else
1002 if (format & PNG_FORMAT_FLAG_ALPHA)
1004 if (format & PNG_FORMAT_FLAG_AFIRST)
1005 return gp_ag16;
1007 else
1008 return gp_ga16;
1011 else
1012 return gp_g16;
1016 else
1018 if (format & PNG_FORMAT_FLAG_COLOR)
1020 if (format & PNG_FORMAT_FLAG_BGR)
1022 if (format & PNG_FORMAT_FLAG_ALPHA)
1024 if (format & PNG_FORMAT_FLAG_AFIRST)
1025 return gp_abgr8;
1027 else
1028 return gp_bgra8;
1031 else
1032 return gp_bgr8;
1035 else
1037 if (format & PNG_FORMAT_FLAG_ALPHA)
1039 if (format & PNG_FORMAT_FLAG_AFIRST)
1040 return gp_argb8;
1042 else
1043 return gp_rgba8;
1046 else
1047 return gp_rgb8;
1051 else
1053 if (format & PNG_FORMAT_FLAG_ALPHA)
1055 if (format & PNG_FORMAT_FLAG_AFIRST)
1056 return gp_ag8;
1058 else
1059 return gp_ga8;
1062 else
1063 return gp_g8;
1068 /* Convertion between pixel formats. The code above effectively eliminates the
1069 * component ordering changes leaving three basic changes:
1071 * 1) Remove an alpha channel by pre-multiplication or compositing on a
1072 * background color. (Adding an alpha channel is a no-op.)
1074 * 2) Remove color by mapping to grayscale. (Grayscale to color is a no-op.)
1076 * 3) Convert between 8-bit and 16-bit components. (Both directtions are
1077 * relevant.)
1079 * This gives the following base format conversion matrix:
1081 * OUT: ----- 8-bit ----- ----- 16-bit -----
1082 * IN G GA RGB RGBA G GA RGB RGBA
1083 * 8 G . . . . lin lin lin lin
1084 * 8 GA bckg . bckc . pre' pre pre' pre
1085 * 8 RGB g8 g8 . . glin glin lin lin
1086 * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre
1087 * 16 G sRGB sRGB sRGB sRGB . . . .
1088 * 16 GA b16g unpg b16c unpc A . A .
1089 * 16 RGB sG sG sRGB sRGB g16 g16 . .
1090 * 16 RGBA gb16 sGp cb16 sCp g16 g16' A .
1092 * 8-bit to 8-bit:
1093 * bckg: composite on gray background
1094 * bckc: composite on color background
1095 * g8: convert sRGB components to sRGB grayscale
1096 * g8b: convert sRGB components to grayscale and composite on gray background
1098 * 8-bit to 16-bit:
1099 * lin: make sRGB components linear, alpha := 65535
1100 * pre: make sRGB components linear and premultiply by alpha (scale alpha)
1101 * pre': as 'pre' but alpha := 65535
1102 * glin: make sRGB components linear, convert to grayscale, alpha := 65535
1103 * gpre: make sRGB components grayscale and linear and premultiply by alpha
1104 * gpr': as 'gpre' but alpha := 65535
1106 * 16-bit to 8-bit:
1107 * sRGB: convert linear components to sRGB, alpha := 255
1108 * unpg: unpremultiply gray component and convert to sRGB (scale alpha)
1109 * unpc: unpremultiply color components and convert to sRGB (scale alpha)
1110 * b16g: composite linear onto gray background and convert the result to sRGB
1111 * b16c: composite linear onto color background and convert the result to sRGB
1112 * sG: convert linear RGB to sRGB grayscale
1113 * sGp: unpremultiply RGB then convert to sRGB grayscale
1114 * sCp: unpremultiply RGB then convert to sRGB
1115 * gb16: composite linear onto background and convert to sRGB grayscale
1116 * (order doesn't matter, the composite and grayscale operations permute)
1117 * cb16: composite linear onto background and convert to sRGB
1119 * 16-bit to 16-bit:
1120 * A: set alpha to 65535
1121 * g16: convert linear RGB to linear grayscale (alpha := 65535)
1122 * g16': as 'g16' but alpha is unchanged
1124 /* Simple copy: */
1125 static void
1126 gpc_noop(Pixel *out, const Pixel *in, const Background *back)
1128 (void)back;
1129 out->r = in->r;
1130 out->g = in->g;
1131 out->b = in->b;
1132 out->a = in->a;
1135 #if ALLOW_UNUSED_GPC
1136 static void
1137 gpc_nop8(Pixel *out, const Pixel *in, const Background *back)
1139 (void)back;
1140 if (in->a == 0)
1141 out->r = out->g = out->b = 255;
1143 else
1145 out->r = in->r;
1146 out->g = in->g;
1147 out->b = in->b;
1150 out->a = in->a;
1152 #endif
1154 #if ALLOW_UNUSED_GPC
1155 static void
1156 gpc_nop6(Pixel *out, const Pixel *in, const Background *back)
1158 (void)back;
1159 if (in->a == 0)
1160 out->r = out->g = out->b = 65535;
1162 else
1164 out->r = in->r;
1165 out->g = in->g;
1166 out->b = in->b;
1169 out->a = in->a;
1171 #endif
1173 /* 8-bit to 8-bit conversions */
1174 /* bckg: composite on gray background */
1175 static void
1176 gpc_bckg(Pixel *out, const Pixel *in, const Background *back)
1178 if (in->a <= 0)
1179 out->r = out->g = out->b = back->ig;
1181 else if (in->a >= 255)
1182 out->r = out->g = out->b = in->g;
1184 else
1186 double a = in->a / 255.;
1188 out->r = out->g = out->b = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a));
1191 out->a = 255;
1194 /* bckc: composite on color background */
1195 static void
1196 gpc_bckc(Pixel *out, const Pixel *in, const Background *back)
1198 if (in->a <= 0)
1200 out->r = back->ir;
1201 out->g = back->ig;
1202 out->b = back->ib;
1205 else if (in->a >= 255)
1207 out->r = in->r;
1208 out->g = in->g;
1209 out->b = in->b;
1212 else
1214 double a = in->a / 255.;
1216 out->r = sRGB(sRGB_to_d[in->r] * a + back->dr * (1-a));
1217 out->g = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a));
1218 out->b = sRGB(sRGB_to_d[in->b] * a + back->db * (1-a));
1221 out->a = 255;
1224 /* g8: convert sRGB components to sRGB grayscale */
1225 static void
1226 gpc_g8(Pixel *out, const Pixel *in, const Background *back)
1228 (void)back;
1230 if (in->r == in->g && in->g == in->b)
1231 out->r = out->g = out->b = in->g;
1233 else
1234 out->r = out->g = out->b =
1235 sRGB(YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b]));
1237 out->a = in->a;
1240 /* g8b: convert sRGB components to grayscale and composite on gray background */
1241 static void
1242 gpc_g8b(Pixel *out, const Pixel *in, const Background *back)
1244 if (in->a <= 0)
1245 out->r = out->g = out->b = back->ig;
1247 else if (in->a >= 255)
1249 if (in->r == in->g && in->g == in->b)
1250 out->r = out->g = out->b = in->g;
1252 else
1253 out->r = out->g = out->b = sRGB(YfromRGB(
1254 sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b]));
1257 else
1259 double a = in->a/255.;
1261 out->r = out->g = out->b = sRGB(a * YfromRGB(sRGB_to_d[in->r],
1262 sRGB_to_d[in->g], sRGB_to_d[in->b]) + back->dg * (1-a));
1265 out->a = 255;
1268 /* 8-bit to 16-bit conversions */
1269 /* lin: make sRGB components linear, alpha := 65535 */
1270 static void
1271 gpc_lin(Pixel *out, const Pixel *in, const Background *back)
1273 (void)back;
1275 out->r = ilinear(in->r);
1277 if (in->g == in->r)
1279 out->g = out->r;
1281 if (in->b == in->r)
1282 out->b = out->r;
1284 else
1285 out->b = ilinear(in->b);
1288 else
1290 out->g = ilinear(in->g);
1292 if (in->b == in->r)
1293 out->b = out->r;
1295 else if (in->b == in->g)
1296 out->b = out->g;
1298 else
1299 out->b = ilinear(in->b);
1302 out->a = 65535;
1305 /* pre: make sRGB components linear and premultiply by alpha (scale alpha) */
1306 static void
1307 gpc_pre(Pixel *out, const Pixel *in, const Background *back)
1309 (void)back;
1311 out->r = ilineara(in->r, in->a);
1313 if (in->g == in->r)
1315 out->g = out->r;
1317 if (in->b == in->r)
1318 out->b = out->r;
1320 else
1321 out->b = ilineara(in->b, in->a);
1324 else
1326 out->g = ilineara(in->g, in->a);
1328 if (in->b == in->r)
1329 out->b = out->r;
1331 else if (in->b == in->g)
1332 out->b = out->g;
1334 else
1335 out->b = ilineara(in->b, in->a);
1338 out->a = in->a * 257;
1341 /* pre': as 'pre' but alpha := 65535 */
1342 static void
1343 gpc_preq(Pixel *out, const Pixel *in, const Background *back)
1345 (void)back;
1347 out->r = ilineara(in->r, in->a);
1349 if (in->g == in->r)
1351 out->g = out->r;
1353 if (in->b == in->r)
1354 out->b = out->r;
1356 else
1357 out->b = ilineara(in->b, in->a);
1360 else
1362 out->g = ilineara(in->g, in->a);
1364 if (in->b == in->r)
1365 out->b = out->r;
1367 else if (in->b == in->g)
1368 out->b = out->g;
1370 else
1371 out->b = ilineara(in->b, in->a);
1374 out->a = 65535;
1377 /* glin: make sRGB components linear, convert to grayscale, alpha := 65535 */
1378 static void
1379 gpc_glin(Pixel *out, const Pixel *in, const Background *back)
1381 (void)back;
1383 if (in->r == in->g && in->g == in->b)
1384 out->r = out->g = out->b = ilinear(in->g);
1386 else
1387 out->r = out->g = out->b = u16d(65535 *
1388 YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b]));
1390 out->a = 65535;
1393 /* gpre: make sRGB components grayscale and linear and premultiply by alpha */
1394 static void
1395 gpc_gpre(Pixel *out, const Pixel *in, const Background *back)
1397 (void)back;
1399 if (in->r == in->g && in->g == in->b)
1400 out->r = out->g = out->b = ilineara(in->g, in->a);
1402 else
1403 out->r = out->g = out->b = u16d(in->a * 257 *
1404 YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b]));
1406 out->a = 257 * in->a;
1409 /* gpr': as 'gpre' but alpha := 65535 */
1410 static void
1411 gpc_gprq(Pixel *out, const Pixel *in, const Background *back)
1413 (void)back;
1415 if (in->r == in->g && in->g == in->b)
1416 out->r = out->g = out->b = ilineara(in->g, in->a);
1418 else
1419 out->r = out->g = out->b = u16d(in->a * 257 *
1420 YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b]));
1422 out->a = 65535;
1425 /* 8-bit to 16-bit conversions for gAMA 45455 encoded values */
1426 /* Lin: make gAMA 45455 components linear, alpha := 65535 */
1427 static void
1428 gpc_Lin(Pixel *out, const Pixel *in, const Background *back)
1430 (void)back;
1432 out->r = ilinear_g22(in->r);
1434 if (in->g == in->r)
1436 out->g = out->r;
1438 if (in->b == in->r)
1439 out->b = out->r;
1441 else
1442 out->b = ilinear_g22(in->b);
1445 else
1447 out->g = ilinear_g22(in->g);
1449 if (in->b == in->r)
1450 out->b = out->r;
1452 else if (in->b == in->g)
1453 out->b = out->g;
1455 else
1456 out->b = ilinear_g22(in->b);
1459 out->a = 65535;
1462 #if ALLOW_UNUSED_GPC
1463 /* Pre: make gAMA 45455 components linear and premultiply by alpha (scale alpha)
1465 static void
1466 gpc_Pre(Pixel *out, const Pixel *in, const Background *back)
1468 (void)back;
1470 out->r = ilineara_g22(in->r, in->a);
1472 if (in->g == in->r)
1474 out->g = out->r;
1476 if (in->b == in->r)
1477 out->b = out->r;
1479 else
1480 out->b = ilineara_g22(in->b, in->a);
1483 else
1485 out->g = ilineara_g22(in->g, in->a);
1487 if (in->b == in->r)
1488 out->b = out->r;
1490 else if (in->b == in->g)
1491 out->b = out->g;
1493 else
1494 out->b = ilineara_g22(in->b, in->a);
1497 out->a = in->a * 257;
1499 #endif
1501 #if ALLOW_UNUSED_GPC
1502 /* Pre': as 'Pre' but alpha := 65535 */
1503 static void
1504 gpc_Preq(Pixel *out, const Pixel *in, const Background *back)
1506 (void)back;
1508 out->r = ilineara_g22(in->r, in->a);
1510 if (in->g == in->r)
1512 out->g = out->r;
1514 if (in->b == in->r)
1515 out->b = out->r;
1517 else
1518 out->b = ilineara_g22(in->b, in->a);
1521 else
1523 out->g = ilineara_g22(in->g, in->a);
1525 if (in->b == in->r)
1526 out->b = out->r;
1528 else if (in->b == in->g)
1529 out->b = out->g;
1531 else
1532 out->b = ilineara_g22(in->b, in->a);
1535 out->a = 65535;
1537 #endif
1539 #if ALLOW_UNUSED_GPC
1540 /* Glin: make gAMA 45455 components linear, convert to grayscale, alpha := 65535
1542 static void
1543 gpc_Glin(Pixel *out, const Pixel *in, const Background *back)
1545 (void)back;
1547 if (in->r == in->g && in->g == in->b)
1548 out->r = out->g = out->b = ilinear_g22(in->g);
1550 else
1551 out->r = out->g = out->b = u16d(65535 *
1552 YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b]));
1554 out->a = 65535;
1556 #endif
1558 #if ALLOW_UNUSED_GPC
1559 /* Gpre: make gAMA 45455 components grayscale and linear and premultiply by
1560 * alpha.
1562 static void
1563 gpc_Gpre(Pixel *out, const Pixel *in, const Background *back)
1565 (void)back;
1567 if (in->r == in->g && in->g == in->b)
1568 out->r = out->g = out->b = ilineara_g22(in->g, in->a);
1570 else
1571 out->r = out->g = out->b = u16d(in->a * 257 *
1572 YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b]));
1574 out->a = 257 * in->a;
1576 #endif
1578 #if ALLOW_UNUSED_GPC
1579 /* Gpr': as 'Gpre' but alpha := 65535 */
1580 static void
1581 gpc_Gprq(Pixel *out, const Pixel *in, const Background *back)
1583 (void)back;
1585 if (in->r == in->g && in->g == in->b)
1586 out->r = out->g = out->b = ilineara_g22(in->g, in->a);
1588 else
1589 out->r = out->g = out->b = u16d(in->a * 257 *
1590 YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b]));
1592 out->a = 65535;
1594 #endif
1596 /* 16-bit to 8-bit conversions */
1597 /* sRGB: convert linear components to sRGB, alpha := 255 */
1598 static void
1599 gpc_sRGB(Pixel *out, const Pixel *in, const Background *back)
1601 (void)back;
1603 out->r = isRGB(in->r);
1605 if (in->g == in->r)
1607 out->g = out->r;
1609 if (in->b == in->r)
1610 out->b = out->r;
1612 else
1613 out->b = isRGB(in->b);
1616 else
1618 out->g = isRGB(in->g);
1620 if (in->b == in->r)
1621 out->b = out->r;
1623 else if (in->b == in->g)
1624 out->b = out->g;
1626 else
1627 out->b = isRGB(in->b);
1630 out->a = 255;
1633 /* unpg: unpremultiply gray component and convert to sRGB (scale alpha) */
1634 static void
1635 gpc_unpg(Pixel *out, const Pixel *in, const Background *back)
1637 (void)back;
1639 if (in->a <= 128)
1641 out->r = out->g = out->b = 255;
1642 out->a = 0;
1645 else
1647 out->r = out->g = out->b = sRGB((double)in->g / in->a);
1648 out->a = u8d(in->a / 257.);
1652 /* unpc: unpremultiply color components and convert to sRGB (scale alpha) */
1653 static void
1654 gpc_unpc(Pixel *out, const Pixel *in, const Background *back)
1656 (void)back;
1658 if (in->a <= 128)
1660 out->r = out->g = out->b = 255;
1661 out->a = 0;
1664 else
1666 out->r = sRGB((double)in->r / in->a);
1667 out->g = sRGB((double)in->g / in->a);
1668 out->b = sRGB((double)in->b / in->a);
1669 out->a = u8d(in->a / 257.);
1673 /* b16g: composite linear onto gray background and convert the result to sRGB */
1674 static void
1675 gpc_b16g(Pixel *out, const Pixel *in, const Background *back)
1677 if (in->a <= 0)
1678 out->r = out->g = out->b = back->ig;
1680 else
1682 double a = in->a/65535.;
1683 double a1 = 1-a;
1685 a /= 65535;
1686 out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1);
1689 out->a = 255;
1692 /* b16c: composite linear onto color background and convert the result to sRGB*/
1693 static void
1694 gpc_b16c(Pixel *out, const Pixel *in, const Background *back)
1696 if (in->a <= 0)
1698 out->r = back->ir;
1699 out->g = back->ig;
1700 out->b = back->ib;
1703 else
1705 double a = in->a/65535.;
1706 double a1 = 1-a;
1708 a /= 65535;
1709 out->r = sRGB(in->r * a + back->dr * a1);
1710 out->g = sRGB(in->g * a + back->dg * a1);
1711 out->b = sRGB(in->b * a + back->db * a1);
1714 out->a = 255;
1717 /* sG: convert linear RGB to sRGB grayscale */
1718 static void
1719 gpc_sG(Pixel *out, const Pixel *in, const Background *back)
1721 (void)back;
1723 out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/65535);
1724 out->a = 255;
1727 /* sGp: unpremultiply RGB then convert to sRGB grayscale */
1728 static void
1729 gpc_sGp(Pixel *out, const Pixel *in, const Background *back)
1731 (void)back;
1733 if (in->a <= 128)
1735 out->r = out->g = out->b = 255;
1736 out->a = 0;
1739 else
1741 out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/in->a);
1742 out->a = u8d(in->a / 257.);
1746 /* sCp: unpremultiply RGB then convert to sRGB */
1747 static void
1748 gpc_sCp(Pixel *out, const Pixel *in, const Background *back)
1750 (void)back;
1752 if (in->a <= 128)
1754 out->r = out->g = out->b = 255;
1755 out->a = 0;
1758 else
1760 out->r = sRGB((double)in->r / in->a);
1761 out->g = sRGB((double)in->g / in->a);
1762 out->b = sRGB((double)in->b / in->a);
1763 out->a = u8d(in->a / 257.);
1767 /* gb16: composite linear onto background and convert to sRGB grayscale */
1768 /* (order doesn't matter, the composite and grayscale operations permute) */
1769 static void
1770 gpc_gb16(Pixel *out, const Pixel *in, const Background *back)
1772 if (in->a <= 0)
1773 out->r = out->g = out->b = back->ig;
1775 else if (in->a >= 65535)
1776 out->r = out->g = out->b = isRGB(in->g);
1778 else
1780 double a = in->a / 65535.;
1781 double a1 = 1-a;
1783 a /= 65535;
1784 out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1);
1787 out->a = 255;
1790 /* cb16: composite linear onto background and convert to sRGB */
1791 static void
1792 gpc_cb16(Pixel *out, const Pixel *in, const Background *back)
1794 if (in->a <= 0)
1796 out->r = back->ir;
1797 out->g = back->ig;
1798 out->b = back->ib;
1801 else if (in->a >= 65535)
1803 out->r = isRGB(in->r);
1804 out->g = isRGB(in->g);
1805 out->b = isRGB(in->b);
1808 else
1810 double a = in->a / 65535.;
1811 double a1 = 1-a;
1813 a /= 65535;
1814 out->r = sRGB(in->r * a + back->dr * a1);
1815 out->g = sRGB(in->g * a + back->dg * a1);
1816 out->b = sRGB(in->b * a + back->db * a1);
1819 out->a = 255;
1822 /* 16-bit to 16-bit conversions */
1823 /* A: set alpha to 65535 */
1824 static void
1825 gpc_A(Pixel *out, const Pixel *in, const Background *back)
1827 (void)back;
1828 out->r = in->r;
1829 out->g = in->g;
1830 out->b = in->b;
1831 out->a = 65535;
1834 /* g16: convert linear RGB to linear grayscale (alpha := 65535) */
1835 static void
1836 gpc_g16(Pixel *out, const Pixel *in, const Background *back)
1838 (void)back;
1839 out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b));
1840 out->a = 65535;
1843 /* g16': as 'g16' but alpha is unchanged */
1844 static void
1845 gpc_g16q(Pixel *out, const Pixel *in, const Background *back)
1847 (void)back;
1848 out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b));
1849 out->a = in->a;
1852 #if ALLOW_UNUSED_GPC
1853 /* Unused functions (to hide them from GCC unused function warnings) */
1854 void (* const gpc_unused[])
1855 (Pixel *out, const Pixel *in, const Background *back) =
1857 gpc_Pre, gpc_Preq, gpc_Glin, gpc_Gpre, gpc_Gprq, gpc_nop8, gpc_nop6
1859 #endif
1861 /* OUT: ----- 8-bit ----- ----- 16-bit -----
1862 * IN G GA RGB RGBA G GA RGB RGBA
1863 * 8 G . . . . lin lin lin lin
1864 * 8 GA bckg . bckc . pre' pre pre' pre
1865 * 8 RGB g8 g8 . . glin glin lin lin
1866 * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre
1867 * 16 G sRGB sRGB sRGB sRGB . . . .
1868 * 16 GA b16g unpg b16c unpc A . A .
1869 * 16 RGB sG sG sRGB sRGB g16 g16 . .
1870 * 16 RGBA gb16 sGp cb16 sCp g16 g16' A .
1872 * The matrix is held in an array indexed thus:
1874 * gpc_fn[out_format & BASE_FORMATS][in_format & BASE_FORMATS];
1876 /* This will produce a compile time error if the FORMAT_FLAG values don't
1877 * match the above matrix!
1879 #if PNG_FORMAT_FLAG_ALPHA == 1 && PNG_FORMAT_FLAG_COLOR == 2 &&\
1880 PNG_FORMAT_FLAG_LINEAR == 4
1881 static void (* const gpc_fn[8/*in*/][8/*out*/])
1882 (Pixel *out, const Pixel *in, const Background *back) =
1884 /*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */
1885 {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_Lin, gpc_Lin, gpc_Lin, gpc_Lin },
1886 {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre },
1887 {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin },
1888 {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre },
1889 {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop},
1890 {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop},
1891 {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop},
1892 {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop}
1895 /* The array is repeated for the cases where both the input and output are color
1896 * mapped because then different algorithms are used.
1898 static void (* const gpc_fn_colormapped[8/*in*/][8/*out*/])
1899 (Pixel *out, const Pixel *in, const Background *back) =
1901 /*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */
1902 {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_lin, gpc_lin, gpc_lin, gpc_lin },
1903 {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre },
1904 {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin },
1905 {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre },
1906 {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop},
1907 {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop},
1908 {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop},
1909 {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop}
1912 /* The error arrays record the error in the same matrix; 64 entries, however
1913 * the different algorithms used in libpng for colormap and direct conversions
1914 * mean that four separate matrices are used (for each combination of
1915 * colormapped and direct.)
1917 * In some cases the conversion between sRGB formats goes via a linear
1918 * intermediate; an sRGB to linear conversion (as above) is followed by a simple
1919 * linear to sRGB step with no other conversions. This is done by a separate
1920 * error array from an arbitrary 'in' format to one of the four basic outputs
1921 * (since final output is always sRGB not colormapped).
1923 * These arrays may be modified if the --accumulate flag is set during the run;
1924 * then instead of logging errors they are simply added in.
1926 * The three entries are currently for transparent, partially transparent and
1927 * opaque input pixel values. Notice that alpha should be exact in each case.
1929 * Errors in alpha should only occur when converting from a direct format
1930 * to a colormapped format, when alpha is effectively smashed (so large
1931 * errors can occur.) There should be no error in the '0' and 'opaque'
1932 * values. The fourth entry in the array is used for the alpha error (and it
1933 * should always be zero for the 'via linear' case since this is never color
1934 * mapped.)
1936 * Mapping to a colormap smashes the colors, it is necessary to have separate
1937 * values for these cases because they are much larger; it is very much
1938 * impossible to obtain a reasonable result, these are held in
1939 * gpc_error_to_colormap.
1941 #if PNG_FORMAT_FLAG_COLORMAP == 8 /* extra check also required */
1942 /* START MACHINE GENERATED */
1943 static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =
1945 { /* input: sRGB-gray */
1946 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1947 { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 },
1948 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1949 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1950 }, { /* input: sRGB-gray+alpha */
1951 { 0, 18, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 },
1952 { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 },
1953 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1954 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1955 }, { /* input: sRGB-rgb */
1956 { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1957 { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 },
1958 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1959 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1960 }, { /* input: sRGB-rgb+alpha */
1961 { 0, 4, 13, 0 }, { 0, 14, 13, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 },
1962 { 0, 832, 764, 0 }, { 0, 832, 764, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 },
1963 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1964 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1965 }, { /* input: linear-gray */
1966 { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
1967 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1968 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1969 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1970 }, { /* input: linear-gray+alpha */
1971 { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 },
1972 { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 },
1973 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1974 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1975 }, { /* input: linear-rgb */
1976 { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
1977 { 0, 0, 4, 0 }, { 0, 0, 4, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1978 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1979 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1980 }, { /* input: linear-rgb+alpha */
1981 { 0, 126, 143, 0 }, { 0, 9, 7, 0 }, { 0, 74, 9, 0 }, { 0, 16, 9, 0 },
1982 { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 },
1983 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1984 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1985 }, { /* input: color-mapped-sRGB-gray */
1986 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1987 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1988 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1989 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1990 }, { /* input: color-mapped-sRGB-gray+alpha */
1991 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1992 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1993 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1994 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
1995 }, { /* input: color-mapped-sRGB-rgb */
1996 { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 8, 0 }, { 0, 0, 8, 0 },
1997 { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 },
1998 { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
1999 { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 }
2000 }, { /* input: color-mapped-sRGB-rgb+alpha */
2001 { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 8, 0 }, { 0, 9, 8, 0 },
2002 { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 409, 0 }, { 0, 717, 409, 0 },
2003 { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 },
2004 { 0, 13323, 460, 0 }, { 0, 334, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 }
2005 }, { /* input: color-mapped-linear-gray */
2006 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2007 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2008 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2009 { 0, 0, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2010 }, { /* input: color-mapped-linear-gray+alpha */
2011 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2012 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2013 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2014 { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2015 }, { /* input: color-mapped-linear-rgb */
2016 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2017 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2018 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2019 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 }
2020 }, { /* input: color-mapped-linear-rgb+alpha */
2021 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2022 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2023 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
2024 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 }
2027 static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =
2029 { /* input: sRGB-gray */
2030 { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }
2031 }, { /* input: sRGB-gray+alpha */
2032 { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 }
2033 }, { /* input: sRGB-rgb */
2034 { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 }
2035 }, { /* input: sRGB-rgb+alpha */
2036 { 0, 12, 14, 0 }, { 0, 180, 14, 0 }, { 0, 14, 15, 0 }, { 0, 186, 15, 0 }
2037 }, { /* input: linear-gray */
2038 { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }
2039 }, { /* input: linear-gray+alpha */
2040 { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }
2041 }, { /* input: linear-rgb */
2042 { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }
2043 }, { /* input: linear-rgb+alpha */
2044 { 0, 1, 1, 0 }, { 0, 8, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }
2045 }, { /* input: color-mapped-sRGB-gray */
2046 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2047 }, { /* input: color-mapped-sRGB-gray+alpha */
2048 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2049 }, { /* input: color-mapped-sRGB-rgb */
2050 { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 }
2051 }, { /* input: color-mapped-sRGB-rgb+alpha */
2052 { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 8, 3, 0 }, { 0, 32, 3, 0 }
2053 }, { /* input: color-mapped-linear-gray */
2054 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2055 }, { /* input: color-mapped-linear-gray+alpha */
2056 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2057 }, { /* input: color-mapped-linear-rgb */
2058 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2059 }, { /* input: color-mapped-linear-rgb+alpha */
2060 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
2063 static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =
2065 { /* input: sRGB-gray */
2066 { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 },
2067 { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }
2068 }, { /* input: sRGB-gray+alpha */
2069 { 0, 19, 2, 0 }, { 0, 255, 2, 25 }, { 0, 88, 2, 0 }, { 0, 255, 2, 25 },
2070 { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }, { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }
2071 }, { /* input: sRGB-rgb */
2072 { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 },
2073 { 0, 0, 937, 0 }, { 0, 0, 937, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 }
2074 }, { /* input: sRGB-rgb+alpha */
2075 { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 220, 25, 0 }, { 0, 255, 25, 67 },
2076 { 0, 17534, 18491, 0 }, { 0, 15614, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 48573, 13677, 17219 }
2077 }, { /* input: linear-gray */
2078 { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 },
2079 { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }
2080 }, { /* input: linear-gray+alpha */
2081 { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 97, 74, 0 }, { 0, 255, 74, 25 },
2082 { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }
2083 }, { /* input: linear-rgb */
2084 { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 },
2085 { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 }
2086 }, { /* input: linear-rgb+alpha */
2087 { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 },
2088 { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 46509, 24992, 17347 }
2091 /* END MACHINE GENERATED */
2092 #endif /* COLORMAP flag check */
2093 #endif /* flag checks */
2095 typedef struct
2097 /* Basic pixel information: */
2098 Image* in_image; /* Input image */
2099 const Image* out_image; /* Output image */
2101 /* 'background' is the value passed to the gpc_ routines, it may be NULL if
2102 * it should not be used (*this* program has an error if it crashes as a
2103 * result!)
2105 Background background_color;
2106 const Background* background;
2108 /* Precalculated values: */
2109 int in_opaque; /* Value of input alpha that is opaque */
2110 int is_palette; /* Sample values come from the palette */
2111 int accumulate; /* Accumlate component errors (don't log) */
2112 int output_8bit; /* Output is 8 bit (else 16 bit) */
2114 void (*in_gp)(Pixel*, png_const_voidp);
2115 void (*out_gp)(Pixel*, png_const_voidp);
2117 void (*transform)(Pixel *out, const Pixel *in, const Background *back);
2118 /* A function to perform the required transform */
2120 void (*from_linear)(Pixel *out, const Pixel *in, const Background *back);
2121 /* For 'via_linear' transforms the final, from linear, step, else NULL */
2123 png_uint_16 error[4];
2124 /* Three error values for transparent, partially transparent and opaque
2125 * input pixels (in turn).
2128 png_uint_16 *error_ptr;
2129 /* Where these are stored in the static array (for 'accumulate') */
2131 Transform;
2133 /* Return a 'transform' as above for the given format conversion. */
2134 static void
2135 transform_from_formats(Transform *result, Image *in_image,
2136 const Image *out_image, png_const_colorp background, int via_linear)
2138 png_uint_32 in_format, out_format;
2139 png_uint_32 in_base, out_base;
2141 memset(result, 0, sizeof *result);
2143 /* Store the original images for error messages */
2144 result->in_image = in_image;
2145 result->out_image = out_image;
2147 in_format = in_image->image.format;
2148 out_format = out_image->image.format;
2150 if (in_format & PNG_FORMAT_FLAG_LINEAR)
2151 result->in_opaque = 65535;
2152 else
2153 result->in_opaque = 255;
2155 result->output_8bit = (out_format & PNG_FORMAT_FLAG_LINEAR) == 0;
2157 result->is_palette = 0; /* set by caller if required */
2158 result->accumulate = (in_image->opts & ACCUMULATE) != 0;
2160 /* The loaders (which need the ordering information) */
2161 result->in_gp = get_pixel(in_format);
2162 result->out_gp = get_pixel(out_format);
2164 /* Remove the ordering information: */
2165 in_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP;
2166 in_base = in_format & BASE_FORMATS;
2167 out_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP;
2168 out_base = out_format & BASE_FORMATS;
2170 if (via_linear)
2172 /* Check for an error in this program: */
2173 if (out_format & (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLORMAP))
2175 fprintf(stderr, "internal transform via linear error 0x%x->0x%x\n",
2176 in_format, out_format);
2177 exit(1);
2180 result->transform = gpc_fn[in_base][out_base | PNG_FORMAT_FLAG_LINEAR];
2181 result->from_linear = gpc_fn[out_base | PNG_FORMAT_FLAG_LINEAR][out_base];
2182 result->error_ptr = gpc_error_via_linear[in_format][out_format];
2185 else if (~in_format & out_format & PNG_FORMAT_FLAG_COLORMAP)
2187 /* The input is not colormapped but the output is, the errors will
2188 * typically be large (only the grayscale-no-alpha case permits preserving
2189 * even 8-bit values.)
2191 result->transform = gpc_fn[in_base][out_base];
2192 result->from_linear = NULL;
2193 result->error_ptr = gpc_error_to_colormap[in_base][out_base];
2196 else
2198 /* The caller handles the colormap->pixel value conversion, so the
2199 * transform function just gets a pixel value, however because libpng
2200 * currently contains a different implementation for mapping a colormap if
2201 * both input and output are colormapped we need different conversion
2202 * functions to deal with errors in the libpng implementation.
2204 if (in_format & out_format & PNG_FORMAT_FLAG_COLORMAP)
2205 result->transform = gpc_fn_colormapped[in_base][out_base];
2206 else
2207 result->transform = gpc_fn[in_base][out_base];
2208 result->from_linear = NULL;
2209 result->error_ptr = gpc_error[in_format][out_format];
2212 /* Follow the libpng simplified API rules to work out what to pass to the gpc
2213 * routines as a background value, if one is not required pass NULL so that
2214 * this program crashes in the even of a programming error.
2216 result->background = NULL; /* default: not required */
2218 /* Rule 1: background only need be supplied if alpha is to be removed */
2219 if (in_format & ~out_format & PNG_FORMAT_FLAG_ALPHA)
2221 /* The input value is 'NULL' to use the background and (otherwise) an sRGB
2222 * background color (to use a solid color). The code above uses a fixed
2223 * byte value, BUFFER_INIT8, for buffer even for 16-bit output. For
2224 * linear (16-bit) output the sRGB background color is ignored; the
2225 * composition is always on the background (so BUFFER_INIT8 * 257), except
2226 * that for the colormap (i.e. linear colormapped output) black is used.
2228 result->background = &result->background_color;
2230 if (out_format & PNG_FORMAT_FLAG_LINEAR || via_linear)
2232 if (out_format & PNG_FORMAT_FLAG_COLORMAP)
2234 result->background_color.ir =
2235 result->background_color.ig =
2236 result->background_color.ib = 0;
2237 result->background_color.dr =
2238 result->background_color.dg =
2239 result->background_color.db = 0;
2242 else
2244 result->background_color.ir =
2245 result->background_color.ig =
2246 result->background_color.ib = BUFFER_INIT8 * 257;
2247 result->background_color.dr =
2248 result->background_color.dg =
2249 result->background_color.db = 0;
2253 else /* sRGB output */
2255 if (background != NULL)
2257 if (out_format & PNG_FORMAT_FLAG_COLOR)
2259 result->background_color.ir = background->red;
2260 result->background_color.ig = background->green;
2261 result->background_color.ib = background->blue;
2262 /* TODO: sometimes libpng uses the power law conversion here, how
2263 * to handle this?
2265 result->background_color.dr = sRGB_to_d[background->red];
2266 result->background_color.dg = sRGB_to_d[background->green];
2267 result->background_color.db = sRGB_to_d[background->blue];
2270 else /* grayscale: libpng only looks at 'g' */
2272 result->background_color.ir =
2273 result->background_color.ig =
2274 result->background_color.ib = background->green;
2275 /* TODO: sometimes libpng uses the power law conversion here, how
2276 * to handle this?
2278 result->background_color.dr =
2279 result->background_color.dg =
2280 result->background_color.db = sRGB_to_d[background->green];
2284 else if ((out_format & PNG_FORMAT_FLAG_COLORMAP) == 0)
2286 result->background_color.ir =
2287 result->background_color.ig =
2288 result->background_color.ib = BUFFER_INIT8;
2289 /* TODO: sometimes libpng uses the power law conversion here, how
2290 * to handle this?
2292 result->background_color.dr =
2293 result->background_color.dg =
2294 result->background_color.db = sRGB_to_d[BUFFER_INIT8];
2297 /* Else the output is colormapped and a background color must be
2298 * provided; if pngstest crashes then that is a bug in this program
2299 * (though libpng should png_error as well.)
2301 else
2302 result->background = NULL;
2306 if (result->background == NULL)
2308 result->background_color.ir =
2309 result->background_color.ig =
2310 result->background_color.ib = -1; /* not used */
2311 result->background_color.dr =
2312 result->background_color.dg =
2313 result->background_color.db = 1E30; /* not used */
2317 /* Copy the error values into the Transform: */
2318 result->error[0] = result->error_ptr[0];
2319 result->error[1] = result->error_ptr[1];
2320 result->error[2] = result->error_ptr[2];
2321 result->error[3] = result->error_ptr[3];
2325 /* Compare two pixels.
2327 * OLD error values:
2328 static int error_to_linear = 811; * by experiment *
2329 static int error_to_linear_grayscale = 424; * by experiment *
2330 static int error_to_sRGB = 6; * by experiment *
2331 static int error_to_sRGB_grayscale = 17; * libpng error by calculation +
2332 2 by experiment *
2333 static int error_in_compose = 2; * by experiment *
2334 static int error_in_premultiply = 1;
2336 * The following is *just* the result of a round trip from 8-bit sRGB to linear
2337 * then back to 8-bit sRGB when it is done by libpng. There are two problems:
2339 * 1) libpng currently uses a 2.2 power law with no linear segment, this results
2340 * in instability in the low values and even with 16-bit precision sRGB(1) ends
2341 * up mapping to sRGB(0) as a result of rounding in the 16-bit representation.
2342 * This gives an error of 1 in the handling of value 1 only.
2344 * 2) libpng currently uses an intermediate 8-bit linear value in gamma
2345 * correction of 8-bit values. This results in many more errors, the worse of
2346 * which is mapping sRGB(14) to sRGB(0).
2348 * The general 'error_via_linear' is more complex because of pre-multiplication,
2349 * this compounds the 8-bit errors according to the alpha value of the pixel.
2350 * As a result 256 values are pre-calculated for error_via_linear.
2352 #if 0
2353 static int error_in_libpng_gamma;
2354 static int error_via_linear[256]; /* Indexed by 8-bit alpha */
2356 static void
2357 init_error_via_linear(void)
2359 int alpha;
2361 error_via_linear[0] = 255; /* transparent pixel */
2363 for (alpha=1; alpha<=255; ++alpha)
2365 /* 16-bit values less than 128.5 get rounded to 8-bit 0 and so the worst
2366 * case error arises with 16-bit 128.5, work out what sRGB
2367 * (non-associated) value generates 128.5; any value less than this is
2368 * going to map to 0, so the worst error is floor(value).
2370 * Note that errors are considerably higher (more than a factor of 2)
2371 * because libpng uses a simple power law for sRGB data at present.
2373 * Add .1 for arithmetic errors inside libpng.
2375 double v = floor(255*pow(.5/*(128.5 * 255 / 65535)*/ / alpha, 1/2.2)+.1);
2377 error_via_linear[alpha] = (int)v;
2380 /* This is actually 14.99, but, despite the closeness to 15, 14 seems to work
2381 * ok in this case.
2383 error_in_libpng_gamma = 14;
2385 #endif
2387 static void
2388 print_pixel(char string[64], const Pixel *pixel, png_uint_32 format)
2390 switch (format & (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR))
2392 case 0:
2393 sprintf(string, "%s(%d)", format_names[format], pixel->g);
2394 break;
2396 case PNG_FORMAT_FLAG_ALPHA:
2397 sprintf(string, "%s(%d,%d)", format_names[format], pixel->g,
2398 pixel->a);
2399 break;
2401 case PNG_FORMAT_FLAG_COLOR:
2402 sprintf(string, "%s(%d,%d,%d)", format_names[format],
2403 pixel->r, pixel->g, pixel->b);
2404 break;
2406 case PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA:
2407 sprintf(string, "%s(%d,%d,%d,%d)", format_names[format],
2408 pixel->r, pixel->g, pixel->b, pixel->a);
2409 break;
2411 default:
2412 sprintf(string, "invalid-format");
2413 break;
2417 static int
2418 logpixel(const Transform *transform, png_uint_32 x, png_uint_32 y,
2419 const Pixel *in, const Pixel *calc, const Pixel *out, const char *reason)
2421 const png_uint_32 in_format = transform->in_image->image.format;
2422 const png_uint_32 out_format = transform->out_image->image.format;
2424 png_uint_32 back_format = out_format & ~PNG_FORMAT_FLAG_ALPHA;
2425 const char *via_linear = "";
2427 char pixel_in[64], pixel_calc[64], pixel_out[64], pixel_loc[64];
2428 char background_info[100];
2430 print_pixel(pixel_in, in, in_format);
2431 print_pixel(pixel_calc, calc, out_format);
2432 print_pixel(pixel_out, out, out_format);
2434 if (transform->is_palette)
2435 sprintf(pixel_loc, "palette: %lu", (unsigned long)y);
2436 else
2437 sprintf(pixel_loc, "%lu,%lu", (unsigned long)x, (unsigned long)y);
2439 if (transform->from_linear != NULL)
2441 via_linear = " (via linear)";
2442 /* And as a result the *read* format which did any background processing
2443 * was itself linear, so the background color information is also
2444 * linear.
2446 back_format |= PNG_FORMAT_FLAG_LINEAR;
2449 if (transform->background != NULL)
2451 Pixel back;
2452 char pixel_back[64];
2454 back.r = transform->background->ir;
2455 back.g = transform->background->ig;
2456 back.b = transform->background->ib;
2457 back.a = -1; /* not used */
2459 print_pixel(pixel_back, &back, back_format);
2460 sprintf(background_info, " on background %s", pixel_back);
2463 else
2464 background_info[0] = 0;
2466 if (transform->in_image->file_name != transform->out_image->file_name)
2468 char error_buffer[512];
2469 sprintf(error_buffer,
2470 "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n"
2471 "Use --preserve and examine: ", pixel_loc, reason, via_linear,
2472 pixel_in, background_info, pixel_out, pixel_calc);
2473 return logerror(transform->in_image, transform->in_image->file_name,
2474 error_buffer, transform->out_image->file_name);
2477 else
2479 char error_buffer[512];
2480 sprintf(error_buffer,
2481 "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n"
2482 " The error happened when reading the original file with this format.",
2483 pixel_loc, reason, via_linear, pixel_in, background_info, pixel_out,
2484 pixel_calc);
2485 return logerror(transform->in_image, transform->in_image->file_name,
2486 error_buffer, "");
2490 static int
2491 cmppixel(Transform *transform, png_const_voidp in, png_const_voidp out,
2492 png_uint_32 x, png_uint_32 y/*or palette index*/)
2494 int maxerr;
2495 png_const_charp errmsg;
2496 Pixel pixel_in, pixel_calc, pixel_out;
2498 transform->in_gp(&pixel_in, in);
2500 if (transform->from_linear == NULL)
2501 transform->transform(&pixel_calc, &pixel_in, transform->background);
2503 else
2505 transform->transform(&pixel_out, &pixel_in, transform->background);
2506 transform->from_linear(&pixel_calc, &pixel_out, NULL);
2509 transform->out_gp(&pixel_out, out);
2511 /* Eliminate the case where the input and output values match exactly. */
2512 if (pixel_calc.a == pixel_out.a && pixel_calc.r == pixel_out.r &&
2513 pixel_calc.g == pixel_out.g && pixel_calc.b == pixel_out.b)
2514 return 1;
2516 /* Eliminate the case where the output pixel is transparent and the output
2517 * is 8-bit - any component values are valid. Don't check the input alpha
2518 * here to also skip the 16-bit small alpha cases.
2520 if (transform->output_8bit && pixel_calc.a == 0 && pixel_out.a == 0)
2521 return 1;
2523 /* Check for alpha errors first; an alpha error can damage the components too
2524 * so avoid spurious checks on components if one is found.
2526 errmsg = NULL;
2528 int err_a = abs(pixel_calc.a-pixel_out.a);
2530 if (err_a > transform->error[3])
2532 /* If accumulating check the components too */
2533 if (transform->accumulate)
2534 transform->error[3] = (png_uint_16)err_a;
2536 else
2537 errmsg = "alpha";
2541 /* Now if *either* of the output alphas are 0 but alpha is within tolerance
2542 * eliminate the 8-bit component comparison.
2544 if (errmsg == NULL && transform->output_8bit &&
2545 (pixel_calc.a == 0 || pixel_out.a == 0))
2546 return 1;
2548 if (errmsg == NULL) /* else just signal an alpha error */
2550 int err_r = abs(pixel_calc.r - pixel_out.r);
2551 int err_g = abs(pixel_calc.g - pixel_out.g);
2552 int err_b = abs(pixel_calc.b - pixel_out.b);
2553 int limit;
2555 if ((err_r | err_g | err_b) == 0)
2556 return 1; /* exact match */
2558 /* Mismatch on a component, check the input alpha */
2559 if (pixel_in.a >= transform->in_opaque)
2561 errmsg = "opaque component";
2562 limit = 2; /* opaque */
2565 else if (pixel_in.a > 0)
2567 errmsg = "alpha component";
2568 limit = 1; /* partially transparent */
2571 else
2573 errmsg = "transparent component (background)";
2574 limit = 0; /* transparent */
2577 maxerr = err_r;
2578 if (maxerr < err_g) maxerr = err_g;
2579 if (maxerr < err_b) maxerr = err_b;
2581 if (maxerr <= transform->error[limit])
2582 return 1; /* within the error limits */
2584 /* Handle a component mis-match; log it, just return an error code, or
2585 * accumulate it.
2587 if (transform->accumulate)
2589 transform->error[limit] = (png_uint_16)maxerr;
2590 return 1; /* to cause the caller to keep going */
2594 /* Failure to match and not accumulating, so the error must be logged. */
2595 return logpixel(transform, x, y, &pixel_in, &pixel_calc, &pixel_out, errmsg);
2598 static png_byte
2599 component_loc(png_byte loc[4], png_uint_32 format)
2601 /* Given a format return the number of channels and the location of
2602 * each channel.
2604 * The mask 'loc' contains the component offset of the channels in the
2605 * following order. Note that if 'format' is grayscale the entries 1-3 must
2606 * all contain the location of the gray channel.
2608 * 0: alpha
2609 * 1: red or gray
2610 * 2: green or gray
2611 * 3: blue or gray
2613 png_byte channels;
2615 if (format & PNG_FORMAT_FLAG_COLOR)
2617 channels = 3;
2619 loc[2] = 1;
2621 if (format & PNG_FORMAT_FLAG_BGR)
2623 loc[1] = 2;
2624 loc[3] = 0;
2627 else
2629 loc[1] = 0;
2630 loc[3] = 2;
2634 else
2636 channels = 1;
2637 loc[1] = loc[2] = loc[3] = 0;
2640 if (format & PNG_FORMAT_FLAG_ALPHA)
2642 if (format & PNG_FORMAT_FLAG_AFIRST)
2644 loc[0] = 0;
2645 ++loc[1];
2646 ++loc[2];
2647 ++loc[3];
2650 else
2651 loc[0] = channels;
2653 ++channels;
2656 else
2657 loc[0] = 4; /* not present */
2659 return channels;
2662 /* Compare two images, the original 'a', which was written out then read back in
2663 * to * give image 'b'. The formats may have been changed.
2665 static int
2666 compare_two_images(Image *a, Image *b, int via_linear,
2667 png_const_colorp background)
2669 ptrdiff_t stridea = a->stride;
2670 ptrdiff_t strideb = b->stride;
2671 png_const_bytep rowa = a->buffer+16;
2672 png_const_bytep rowb = b->buffer+16;
2673 const png_uint_32 width = a->image.width;
2674 const png_uint_32 height = a->image.height;
2675 const png_uint_32 formata = a->image.format;
2676 const png_uint_32 formatb = b->image.format;
2677 const unsigned int a_sample = PNG_IMAGE_SAMPLE_SIZE(formata);
2678 const unsigned int b_sample = PNG_IMAGE_SAMPLE_SIZE(formatb);
2679 int alpha_added, alpha_removed;
2680 int bchannels;
2681 int btoa[4];
2682 png_uint_32 y;
2683 Transform tr;
2685 /* This should never happen: */
2686 if (width != b->image.width || height != b->image.height)
2687 return logerror(a, a->file_name, ": width x height changed: ",
2688 b->file_name);
2690 /* Set up the background and the transform */
2691 transform_from_formats(&tr, a, b, background, via_linear);
2693 /* Find the first row and inter-row space. */
2694 if (!(formata & PNG_FORMAT_FLAG_COLORMAP) &&
2695 (formata & PNG_FORMAT_FLAG_LINEAR))
2696 stridea *= 2;
2698 if (!(formatb & PNG_FORMAT_FLAG_COLORMAP) &&
2699 (formatb & PNG_FORMAT_FLAG_LINEAR))
2700 strideb *= 2;
2702 if (stridea < 0) rowa += (height-1) * (-stridea);
2703 if (strideb < 0) rowb += (height-1) * (-strideb);
2705 /* First shortcut the two colormap case by comparing the image data; if it
2706 * matches then we expect the colormaps to match, although this is not
2707 * absolutely necessary for an image match. If the colormaps fail to match
2708 * then there is a problem in libpng.
2710 if (formata & formatb & PNG_FORMAT_FLAG_COLORMAP)
2712 /* Only check colormap entries that actually exist; */
2713 png_const_bytep ppa, ppb;
2714 int match;
2715 png_byte in_use[256], amax = 0, bmax = 0;
2717 memset(in_use, 0, sizeof in_use);
2719 ppa = rowa;
2720 ppb = rowb;
2722 /* Do this the slow way to accumulate the 'in_use' flags, don't break out
2723 * of the loop until the end; this validates the color-mapped data to
2724 * ensure all pixels are valid color-map indexes.
2726 for (y=0, match=1; y<height && match; ++y, ppa += stridea, ppb += strideb)
2728 png_uint_32 x;
2730 for (x=0; x<width; ++x)
2732 png_byte bval = ppb[x];
2733 png_byte aval = ppa[x];
2735 if (bval > bmax)
2736 bmax = bval;
2738 if (bval != aval)
2739 match = 0;
2741 in_use[aval] = 1;
2742 if (aval > amax)
2743 amax = aval;
2747 /* If the buffers match then the colormaps must too. */
2748 if (match)
2750 /* Do the color-maps match, entry by entry? Only check the 'in_use'
2751 * entries. An error here should be logged as a color-map error.
2753 png_const_bytep a_cmap = (png_const_bytep)a->colormap;
2754 png_const_bytep b_cmap = (png_const_bytep)b->colormap;
2755 int result = 1; /* match by default */
2757 /* This is used in logpixel to get the error message correct. */
2758 tr.is_palette = 1;
2760 for (y=0; y<256; ++y, a_cmap += a_sample, b_cmap += b_sample)
2761 if (in_use[y])
2763 /* The colormap entries should be valid, but because libpng doesn't
2764 * do any checking at present the original image may contain invalid
2765 * pixel values. These cause an error here (at present) unless
2766 * accumulating errors in which case the program just ignores them.
2768 if (y >= a->image.colormap_entries)
2770 if ((a->opts & ACCUMULATE) == 0)
2772 char pindex[9];
2773 sprintf(pindex, "%lu[%lu]", (unsigned long)y,
2774 (unsigned long)a->image.colormap_entries);
2775 logerror(a, a->file_name, ": bad pixel index: ", pindex);
2777 result = 0;
2780 else if (y >= b->image.colormap_entries)
2782 if ((a->opts & ACCUMULATE) == 0)
2784 char pindex[9];
2785 sprintf(pindex, "%lu[%lu]", (unsigned long)y,
2786 (unsigned long)b->image.colormap_entries);
2787 logerror(b, b->file_name, ": bad pixel index: ", pindex);
2789 result = 0;
2792 /* All the mismatches are logged here; there can only be 256! */
2793 else if (!cmppixel(&tr, a_cmap, b_cmap, 0, y))
2794 result = 0;
2797 /* If reqested copy the error values back from the Transform. */
2798 if (a->opts & ACCUMULATE)
2800 tr.error_ptr[0] = tr.error[0];
2801 tr.error_ptr[1] = tr.error[1];
2802 tr.error_ptr[2] = tr.error[2];
2803 tr.error_ptr[3] = tr.error[3];
2804 result = 1; /* force a continue */
2807 return result;
2810 /* else the image buffers don't match pixel-wise so compare sample values
2811 * instead, but first validate that the pixel indexes are in range (but
2812 * only if not accumulating, when the error is ignored.)
2814 else if ((a->opts & ACCUMULATE) == 0)
2816 /* Check the original image first,
2817 * TODO: deal with input images with bad pixel values?
2819 if (amax >= a->image.colormap_entries)
2821 char pindex[9];
2822 sprintf(pindex, "%d[%lu]", amax,
2823 (unsigned long)a->image.colormap_entries);
2824 return logerror(a, a->file_name, ": bad pixel index: ", pindex);
2827 else if (bmax >= b->image.colormap_entries)
2829 char pindex[9];
2830 sprintf(pindex, "%d[%lu]", bmax,
2831 (unsigned long)b->image.colormap_entries);
2832 return logerror(b, b->file_name, ": bad pixel index: ", pindex);
2837 /* We can directly compare pixel values without the need to use the read
2838 * or transform support (i.e. a memory compare) if:
2840 * 1) The bit depth has not changed.
2841 * 2) RGB to grayscale has not been done (the reverse is ok; we just compare
2842 * the three RGB values to the original grayscale.)
2843 * 3) An alpha channel has not been removed from an 8-bit format, or the
2844 * 8-bit alpha value of the pixel was 255 (opaque).
2846 * If an alpha channel has been *added* then it must have the relevant opaque
2847 * value (255 or 65535).
2849 * The fist two the tests (in the order given above) (using the boolean
2850 * equivalence !a && !b == !(a || b))
2852 if (!(((formata ^ formatb) & PNG_FORMAT_FLAG_LINEAR) |
2853 (formata & (formatb ^ PNG_FORMAT_FLAG_COLOR) & PNG_FORMAT_FLAG_COLOR)))
2855 /* Was an alpha channel changed? */
2856 const png_uint_32 alpha_changed = (formata ^ formatb) &
2857 PNG_FORMAT_FLAG_ALPHA;
2859 /* Was an alpha channel removed? (The third test.) If so the direct
2860 * comparison is only possible if the input alpha is opaque.
2862 alpha_removed = (formata & alpha_changed) != 0;
2864 /* Was an alpha channel added? */
2865 alpha_added = (formatb & alpha_changed) != 0;
2867 /* The channels may have been moved between input and output, this finds
2868 * out how, recording the result in the btoa array, which says where in
2869 * 'a' to find each channel of 'b'. If alpha was added then btoa[alpha]
2870 * ends up as 4 (and is not used.)
2873 int i;
2874 png_byte aloc[4];
2875 png_byte bloc[4];
2877 /* The following are used only if the formats match, except that
2878 * 'bchannels' is a flag for matching formats. btoa[x] says, for each
2879 * channel in b, where to find the corresponding value in a, for the
2880 * bchannels. achannels may be different for a gray to rgb transform
2881 * (a will be 1 or 2, b will be 3 or 4 channels.)
2883 (void)component_loc(aloc, formata);
2884 bchannels = component_loc(bloc, formatb);
2886 /* Hence the btoa array. */
2887 for (i=0; i<4; ++i) if (bloc[i] < 4)
2888 btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */
2890 if (alpha_added)
2891 alpha_added = bloc[0]; /* location of alpha channel in image b */
2893 else
2894 alpha_added = 4; /* Won't match an image b channel */
2896 if (alpha_removed)
2897 alpha_removed = aloc[0]; /* location of alpha channel in image a */
2899 else
2900 alpha_removed = 4;
2904 else
2906 /* Direct compare is not possible, cancel out all the corresponding local
2907 * variables.
2909 bchannels = 0;
2910 alpha_removed = alpha_added = 4;
2911 btoa[3] = btoa[2] = btoa[1] = btoa[0] = 4; /* 4 == not present */
2914 for (y=0; y<height; ++y, rowa += stridea, rowb += strideb)
2916 png_const_bytep ppa, ppb;
2917 png_uint_32 x;
2919 for (x=0, ppa=rowa, ppb=rowb; x<width; ++x)
2921 png_const_bytep psa, psb;
2923 if (formata & PNG_FORMAT_FLAG_COLORMAP)
2924 psa = (png_const_bytep)a->colormap + a_sample * *ppa++;
2925 else
2926 psa = ppa, ppa += a_sample;
2928 if (formatb & PNG_FORMAT_FLAG_COLORMAP)
2929 psb = (png_const_bytep)b->colormap + b_sample * *ppb++;
2930 else
2931 psb = ppb, ppb += b_sample;
2933 /* Do the fast test if possible. */
2934 if (bchannels)
2936 /* Check each 'b' channel against either the corresponding 'a'
2937 * channel or the opaque alpha value, as appropriate. If
2938 * alpha_removed value is set (not 4) then also do this only if the
2939 * 'a' alpha channel (alpha_removed) is opaque; only relevant for
2940 * the 8-bit case.
2942 if (formatb & PNG_FORMAT_FLAG_LINEAR) /* 16-bit checks */
2944 png_const_uint_16p pua = aligncastconst(png_const_uint_16p, psa);
2945 png_const_uint_16p pub = aligncastconst(png_const_uint_16p, psb);
2947 switch (bchannels)
2949 case 4:
2950 if (pua[btoa[3]] != pub[3]) break;
2951 case 3:
2952 if (pua[btoa[2]] != pub[2]) break;
2953 case 2:
2954 if (pua[btoa[1]] != pub[1]) break;
2955 case 1:
2956 if (pua[btoa[0]] != pub[0]) break;
2957 if (alpha_added != 4 && pub[alpha_added] != 65535) break;
2958 continue; /* x loop */
2959 default:
2960 break; /* impossible */
2964 else if (alpha_removed == 4 || psa[alpha_removed] == 255)
2966 switch (bchannels)
2968 case 4:
2969 if (psa[btoa[3]] != psb[3]) break;
2970 case 3:
2971 if (psa[btoa[2]] != psb[2]) break;
2972 case 2:
2973 if (psa[btoa[1]] != psb[1]) break;
2974 case 1:
2975 if (psa[btoa[0]] != psb[0]) break;
2976 if (alpha_added != 4 && psb[alpha_added] != 255) break;
2977 continue; /* x loop */
2978 default:
2979 break; /* impossible */
2984 /* If we get to here the fast match failed; do the slow match for this
2985 * pixel.
2987 if (!cmppixel(&tr, psa, psb, x, y) && (a->opts & KEEP_GOING) == 0)
2988 return 0; /* error case */
2992 /* If reqested copy the error values back from the Transform. */
2993 if (a->opts & ACCUMULATE)
2995 tr.error_ptr[0] = tr.error[0];
2996 tr.error_ptr[1] = tr.error[1];
2997 tr.error_ptr[2] = tr.error[2];
2998 tr.error_ptr[3] = tr.error[3];
3001 return 1;
3004 /* Read the file; how the read gets done depends on which of input_file and
3005 * input_memory have been set.
3007 static int
3008 read_file(Image *image, png_uint_32 format, png_const_colorp background)
3010 memset(&image->image, 0, sizeof image->image);
3011 image->image.version = PNG_IMAGE_VERSION;
3013 if (image->input_memory != NULL)
3015 if (!png_image_begin_read_from_memory(&image->image, image->input_memory,
3016 image->input_memory_size))
3017 return logerror(image, "memory init: ", image->file_name, "");
3020 else if (image->input_file != NULL)
3022 if (!png_image_begin_read_from_stdio(&image->image, image->input_file))
3023 return logerror(image, "stdio init: ", image->file_name, "");
3026 else
3028 if (!png_image_begin_read_from_file(&image->image, image->file_name))
3029 return logerror(image, "file init: ", image->file_name, "");
3032 /* This must be set after the begin_read call: */
3033 if (image->opts & sRGB_16BIT)
3034 image->image.flags |= PNG_IMAGE_FLAG_16BIT_sRGB;
3036 /* Have an initialized image with all the data we need plus, maybe, an
3037 * allocated file (myfile) or buffer (mybuffer) that need to be freed.
3040 int result;
3041 png_uint_32 image_format;
3043 /* Print both original and output formats. */
3044 image_format = image->image.format;
3046 if (image->opts & VERBOSE)
3048 printf("%s %lu x %lu %s -> %s", image->file_name,
3049 (unsigned long)image->image.width,
3050 (unsigned long)image->image.height,
3051 format_names[image_format & FORMAT_MASK],
3052 (format & FORMAT_NO_CHANGE) != 0 || image->image.format == format
3053 ? "no change" : format_names[format & FORMAT_MASK]);
3055 if (background != NULL)
3056 printf(" background(%d,%d,%d)\n", background->red,
3057 background->green, background->blue);
3058 else
3059 printf("\n");
3061 fflush(stdout);
3064 /* 'NO_CHANGE' combined with the color-map flag forces the base format
3065 * flags to be set on read to ensure that the original representation is
3066 * not lost in the pass through a colormap format.
3068 if ((format & FORMAT_NO_CHANGE) != 0)
3070 if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 &&
3071 (image_format & PNG_FORMAT_FLAG_COLORMAP) != 0)
3072 format = (image_format & ~BASE_FORMATS) | (format & BASE_FORMATS);
3074 else
3075 format = image_format;
3078 image->image.format = format;
3080 image->stride = PNG_IMAGE_ROW_STRIDE(image->image) + image->stride_extra;
3081 allocbuffer(image);
3083 result = png_image_finish_read(&image->image, background,
3084 image->buffer+16, (png_int_32)image->stride, image->colormap);
3086 checkbuffer(image, image->file_name);
3088 if (result)
3089 return checkopaque(image);
3091 else
3092 return logerror(image, image->file_name, ": image read failed", "");
3096 /* Reads from a filename, which must be in image->file_name, but uses
3097 * image->opts to choose the method. The file is always read in its native
3098 * format (the one the simplified API suggests).
3100 static int
3101 read_one_file(Image *image)
3103 if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO))
3105 /* memory or stdio. */
3106 FILE *f = fopen(image->file_name, "rb");
3108 if (f != NULL)
3110 if (image->opts & READ_FILE)
3111 image->input_file = f;
3113 else /* memory */
3115 if (fseek(f, 0, SEEK_END) == 0)
3117 long int cb = ftell(f);
3119 if (cb > 0 && (unsigned long int)cb < (size_t)~(size_t)0)
3121 png_bytep b = voidcast(png_bytep, malloc((size_t)cb));
3123 if (b != NULL)
3125 rewind(f);
3127 if (fread(b, (size_t)cb, 1, f) == 1)
3129 fclose(f);
3130 image->input_memory_size = cb;
3131 image->input_memory = b;
3134 else
3136 free(b);
3137 return logclose(image, f, image->file_name,
3138 ": read failed: ");
3142 else
3143 return logclose(image, f, image->file_name,
3144 ": out of memory: ");
3147 else if (cb == 0)
3148 return logclose(image, f, image->file_name,
3149 ": zero length: ");
3151 else
3152 return logclose(image, f, image->file_name,
3153 ": tell failed: ");
3156 else
3157 return logclose(image, f, image->file_name, ": seek failed: ");
3161 else
3162 return logerror(image, image->file_name, ": open failed: ",
3163 strerror(errno));
3166 return read_file(image, FORMAT_NO_CHANGE, NULL);
3169 #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
3170 static int
3171 write_one_file(Image *output, Image *image, int convert_to_8bit)
3173 if (image->opts & FAST_WRITE)
3174 image->image.flags |= PNG_IMAGE_FLAG_FAST;
3176 if (image->opts & USE_STDIO)
3178 FILE *f = tmpfile();
3180 if (f != NULL)
3182 if (png_image_write_to_stdio(&image->image, f, convert_to_8bit,
3183 image->buffer+16, (png_int_32)image->stride, image->colormap))
3185 if (fflush(f) == 0)
3187 rewind(f);
3188 initimage(output, image->opts, "tmpfile", image->stride_extra);
3189 output->input_file = f;
3190 if (!checkopaque(image))
3191 return 0;
3194 else
3195 return logclose(image, f, "tmpfile", ": flush: ");
3198 else
3200 fclose(f);
3201 return logerror(image, "tmpfile", ": write failed", "");
3205 else
3206 return logerror(image, "tmpfile", ": open: ", strerror(errno));
3209 else
3211 static int counter = 0;
3212 char name[32];
3214 sprintf(name, "%s%d.png", tmpf, ++counter);
3216 if (png_image_write_to_file(&image->image, name, convert_to_8bit,
3217 image->buffer+16, (png_int_32)image->stride, image->colormap))
3219 initimage(output, image->opts, output->tmpfile_name,
3220 image->stride_extra);
3221 /* Afterwards, or freeimage will delete it! */
3222 strcpy(output->tmpfile_name, name);
3224 if (!checkopaque(image))
3225 return 0;
3228 else
3229 return logerror(image, name, ": write failed", "");
3232 /* 'output' has an initialized temporary image, read this back in and compare
3233 * this against the original: there should be no change since the original
3234 * format was written unmodified unless 'convert_to_8bit' was specified.
3235 * However, if the original image was color-mapped, a simple read will zap
3236 * the linear, color and maybe alpha flags, this will cause spurious failures
3237 * under some circumstances.
3239 if (read_file(output, image->image.format | FORMAT_NO_CHANGE, NULL))
3241 png_uint_32 original_format = image->image.format;
3243 if (convert_to_8bit)
3244 original_format &= ~PNG_FORMAT_FLAG_LINEAR;
3246 if ((output->image.format & BASE_FORMATS) !=
3247 (original_format & BASE_FORMATS))
3248 return logerror(image, image->file_name, ": format changed on read: ",
3249 output->file_name);
3251 return compare_two_images(image, output, 0/*via linear*/, NULL);
3254 else
3255 return logerror(output, output->tmpfile_name,
3256 ": read of new file failed", "");
3258 #endif
3260 static int
3261 testimage(Image *image, png_uint_32 opts, format_list *pf)
3263 int result;
3264 Image copy;
3266 /* Copy the original data, stealing it from 'image' */
3267 checkopaque(image);
3268 copy = *image;
3270 copy.opts = opts;
3271 copy.buffer = NULL;
3272 copy.bufsize = 0;
3273 copy.allocsize = 0;
3275 image->input_file = NULL;
3276 image->input_memory = NULL;
3277 image->input_memory_size = 0;
3278 image->tmpfile_name[0] = 0;
3281 png_uint_32 counter;
3282 Image output;
3284 newimage(&output);
3286 result = 1;
3288 /* Use the low bit of 'counter' to indicate whether or not to do alpha
3289 * removal with a background color or by composting onto the image; this
3290 * step gets skipped if it isn't relevant
3292 for (counter=0; counter<2*FORMAT_COUNT; ++counter)
3293 if (format_isset(pf, counter >> 1))
3295 png_uint_32 format = counter >> 1;
3297 png_color background_color;
3298 png_colorp background = NULL;
3300 /* If there is a format change that removes the alpha channel then
3301 * the background is relevant. If the output is 8-bit color-mapped
3302 * then a background color *must* be provided, otherwise there are
3303 * two tests to do - one with a color, the other with NULL. The
3304 * NULL test happens second.
3306 if ((counter & 1) == 0)
3308 if ((format & PNG_FORMAT_FLAG_ALPHA) == 0 &&
3309 (image->image.format & PNG_FORMAT_FLAG_ALPHA) != 0)
3311 /* Alpha/transparency will be removed, the background is
3312 * relevant: make it a color the first time
3314 random_color(&background_color);
3315 background = &background_color;
3317 /* BUT if the output is to a color-mapped 8-bit format then
3318 * the background must always be a color, so increment 'counter'
3319 * to skip the NULL test.
3321 if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 &&
3322 (format & PNG_FORMAT_FLAG_LINEAR) == 0)
3323 ++counter;
3326 /* Otherwise an alpha channel is not being eliminated, just leave
3327 * background NULL and skip the (counter & 1) NULL test.
3329 else
3330 ++counter;
3332 /* else just use NULL for background */
3334 resetimage(&copy);
3335 copy.opts = opts; /* in case read_file needs to change it */
3337 result = read_file(&copy, format, background);
3338 if (!result)
3339 break;
3341 /* Make sure the file just read matches the original file. */
3342 result = compare_two_images(image, &copy, 0/*via linear*/, background);
3343 if (!result)
3344 break;
3346 # ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
3347 /* Write the *copy* just made to a new file to make sure the write
3348 * side works ok. Check the conversion to sRGB if the copy is
3349 * linear.
3351 output.opts = opts;
3352 result = write_one_file(&output, &copy, 0/*convert to 8bit*/);
3353 if (!result)
3354 break;
3356 /* Validate against the original too; the background is needed here
3357 * as well so that compare_two_images knows what color was used.
3359 result = compare_two_images(image, &output, 0, background);
3360 if (!result)
3361 break;
3363 if ((format & PNG_FORMAT_FLAG_LINEAR) != 0 &&
3364 (format & PNG_FORMAT_FLAG_COLORMAP) == 0)
3366 /* 'output' is linear, convert to the corresponding sRGB format.
3368 output.opts = opts;
3369 result = write_one_file(&output, &copy, 1/*convert to 8bit*/);
3370 if (!result)
3371 break;
3373 /* This may involve a conversion via linear; in the ideal world
3374 * this would round-trip correctly, but libpng 1.5.7 is not the
3375 * ideal world so allow a drift (error_via_linear).
3377 * 'image' has an alpha channel but 'output' does not then there
3378 * will a strip-alpha-channel operation (because 'output' is
3379 * linear), handle this by composing on black when doing the
3380 * comparison.
3382 result = compare_two_images(image, &output, 1/*via_linear*/,
3383 background);
3384 if (!result)
3385 break;
3387 # endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */
3390 freeimage(&output);
3393 freeimage(&copy);
3395 return result;
3398 static int
3399 test_one_file(const char *file_name, format_list *formats, png_uint_32 opts,
3400 int stride_extra, int log_pass)
3402 int result;
3403 Image image;
3405 newimage(&image);
3406 initimage(&image, opts, file_name, stride_extra);
3407 result = read_one_file(&image);
3408 if (result)
3409 result = testimage(&image, opts, formats);
3410 freeimage(&image);
3412 /* Ensure that stderr is flushed into any log file */
3413 fflush(stderr);
3415 if (log_pass)
3417 if (result)
3418 printf("PASS:");
3420 else
3421 printf("FAIL:");
3423 # ifndef PNG_SIMPLIFIED_WRITE_SUPPORTED
3424 printf(" (no write)");
3425 # endif
3427 print_opts(opts);
3428 printf(" %s\n", file_name);
3429 /* stdout may not be line-buffered if it is piped to a file, so: */
3430 fflush(stdout);
3433 else if (!result)
3434 exit(1);
3436 return result;
3440 main(int argc, char **argv)
3442 png_uint_32 opts = FAST_WRITE;
3443 format_list formats;
3444 const char *touch = NULL;
3445 int log_pass = 0;
3446 int redundant = 0;
3447 int stride_extra = 0;
3448 int retval = 0;
3449 int c;
3451 init_sRGB_to_d();
3452 #if 0
3453 init_error_via_linear();
3454 #endif
3455 format_init(&formats);
3457 for (c=1; c<argc; ++c)
3459 const char *arg = argv[c];
3461 if (strcmp(arg, "--log") == 0)
3462 log_pass = 1;
3463 else if (strcmp(arg, "--fresh") == 0)
3465 memset(gpc_error, 0, sizeof gpc_error);
3466 memset(gpc_error_via_linear, 0, sizeof gpc_error_via_linear);
3468 else if (strcmp(arg, "--file") == 0)
3469 opts |= READ_FILE;
3470 else if (strcmp(arg, "--memory") == 0)
3471 opts &= ~READ_FILE;
3472 else if (strcmp(arg, "--stdio") == 0)
3473 opts |= USE_STDIO;
3474 else if (strcmp(arg, "--name") == 0)
3475 opts &= ~USE_STDIO;
3476 else if (strcmp(arg, "--verbose") == 0)
3477 opts |= VERBOSE;
3478 else if (strcmp(arg, "--quiet") == 0)
3479 opts &= ~VERBOSE;
3480 else if (strcmp(arg, "--preserve") == 0)
3481 opts |= KEEP_TMPFILES;
3482 else if (strcmp(arg, "--nopreserve") == 0)
3483 opts &= ~KEEP_TMPFILES;
3484 else if (strcmp(arg, "--keep-going") == 0)
3485 opts |= KEEP_GOING;
3486 else if (strcmp(arg, "--fast") == 0)
3487 opts |= FAST_WRITE;
3488 else if (strcmp(arg, "--slow") == 0)
3489 opts &= ~FAST_WRITE;
3490 else if (strcmp(arg, "--accumulate") == 0)
3491 opts |= ACCUMULATE;
3492 else if (strcmp(arg, "--redundant") == 0)
3493 redundant = 1;
3494 else if (strcmp(arg, "--stop") == 0)
3495 opts &= ~KEEP_GOING;
3496 else if (strcmp(arg, "--strict") == 0)
3497 opts |= STRICT;
3498 else if (strcmp(arg, "--sRGB-16bit") == 0)
3499 opts |= sRGB_16BIT;
3500 else if (strcmp(arg, "--linear-16bit") == 0)
3501 opts &= ~sRGB_16BIT;
3502 else if (strcmp(arg, "--tmpfile") == 0)
3504 if (c+1 < argc)
3506 if (strlen(argv[++c]) >= sizeof tmpf)
3508 fflush(stdout);
3509 fprintf(stderr, "%s: %s is too long for a temp file prefix\n",
3510 argv[0], argv[c]);
3511 exit(99);
3514 /* Safe: checked above */
3515 strcpy(tmpf, argv[c]);
3518 else
3520 fflush(stdout);
3521 fprintf(stderr, "%s: %s requires a temporary file prefix\n",
3522 argv[0], arg);
3523 exit(99);
3526 else if (strcmp(arg, "--touch") == 0)
3528 if (c+1 < argc)
3529 touch = argv[++c];
3531 else
3533 fflush(stdout);
3534 fprintf(stderr, "%s: %s requires a file name argument\n",
3535 argv[0], arg);
3536 exit(99);
3539 else if (arg[0] == '+')
3541 png_uint_32 format = formatof(arg+1);
3543 if (format > FORMAT_COUNT)
3544 exit(99);
3546 format_set(&formats, format);
3548 else if (arg[0] == '-' && arg[1] != 0 && (arg[1] != '0' || arg[2] != 0))
3550 fflush(stdout);
3551 fprintf(stderr, "%s: unknown option: %s\n", argv[0], arg);
3552 exit(99);
3554 else
3556 if (format_is_initial(&formats))
3557 format_default(&formats, redundant);
3559 if (arg[0] == '-')
3561 const int term = (arg[1] == '0' ? 0 : '\n');
3562 unsigned int ich = 0;
3564 /* Loop reading files, use a static buffer to simplify this and just
3565 * stop if the name gets to long.
3567 static char buffer[4096];
3571 int ch = getchar();
3573 /* Don't allow '\0' in file names, and terminate with '\n' or,
3574 * for -0, just '\0' (use -print0 to find to make this work!)
3576 if (ch == EOF || ch == term || ch == 0)
3578 buffer[ich] = 0;
3580 if (ich > 0 && !test_one_file(buffer, &formats, opts,
3581 stride_extra, log_pass))
3582 retval = 1;
3584 if (ch == EOF)
3585 break;
3587 ich = 0;
3588 --ich; /* so that the increment below sets it to 0 again */
3591 else
3592 buffer[ich] = (char)ch;
3593 } while (++ich < sizeof buffer);
3595 if (ich)
3597 buffer[32] = 0;
3598 buffer[4095] = 0;
3599 fprintf(stderr, "%s...%s: file name too long\n", buffer,
3600 buffer+(4096-32));
3601 exit(99);
3605 else if (!test_one_file(arg, &formats, opts, stride_extra, log_pass))
3606 retval = 1;
3610 if (opts & ACCUMULATE)
3612 unsigned int in;
3614 printf("static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =\n");
3615 printf("{\n");
3616 for (in=0; in<16; ++in)
3618 unsigned int out;
3619 printf(" { /* input: %s */\n ", format_names[in]);
3620 for (out=0; out<16; ++out)
3622 unsigned int alpha;
3623 printf(" {");
3624 for (alpha=0; alpha<4; ++alpha)
3626 printf(" %d", gpc_error[in][out][alpha]);
3627 if (alpha < 3) putchar(',');
3629 printf(" }");
3630 if (out < 15)
3632 putchar(',');
3633 if (out % 4 == 3) printf("\n ");
3636 printf("\n }");
3638 if (in < 15)
3639 putchar(',');
3640 else
3641 putchar('\n');
3643 printf("};\n");
3645 printf("static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =\n");
3646 printf("{\n");
3647 for (in=0; in<16; ++in)
3649 unsigned int out;
3650 printf(" { /* input: %s */\n ", format_names[in]);
3651 for (out=0; out<4; ++out)
3653 unsigned int alpha;
3654 printf(" {");
3655 for (alpha=0; alpha<4; ++alpha)
3657 printf(" %d", gpc_error_via_linear[in][out][alpha]);
3658 if (alpha < 3) putchar(',');
3660 printf(" }");
3661 if (out < 3)
3662 putchar(',');
3664 printf("\n }");
3666 if (in < 15)
3667 putchar(',');
3668 else
3669 putchar('\n');
3671 printf("};\n");
3673 printf("static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =\n");
3674 printf("{\n");
3675 for (in=0; in<8; ++in)
3677 unsigned int out;
3678 printf(" { /* input: %s */\n ", format_names[in]);
3679 for (out=0; out<8; ++out)
3681 unsigned int alpha;
3682 printf(" {");
3683 for (alpha=0; alpha<4; ++alpha)
3685 printf(" %d", gpc_error_to_colormap[in][out][alpha]);
3686 if (alpha < 3) putchar(',');
3688 printf(" }");
3689 if (out < 7)
3691 putchar(',');
3692 if (out % 4 == 3) printf("\n ");
3695 printf("\n }");
3697 if (in < 7)
3698 putchar(',');
3699 else
3700 putchar('\n');
3702 printf("};\n");
3705 if (retval == 0 && touch != NULL)
3707 FILE *fsuccess = fopen(touch, "wt");
3709 if (fsuccess != NULL)
3711 int error = 0;
3712 fprintf(fsuccess, "PNG simple API tests succeeded\n");
3713 fflush(fsuccess);
3714 error = ferror(fsuccess);
3716 if (fclose(fsuccess) || error)
3718 fflush(stdout);
3719 fprintf(stderr, "%s: write failed\n", touch);
3720 exit(99);
3724 else
3726 fflush(stdout);
3727 fprintf(stderr, "%s: open failed\n", touch);
3728 exit(99);
3732 return retval;
3735 #else /* !PNG_SIMPLIFIED_READ_SUPPORTED */
3736 int main(void)
3738 fprintf(stderr, "pngstest: no read support in libpng, test skipped\n");
3739 /* So the test is skipped: */
3740 return 77;
3742 #endif /* PNG_SIMPLIFIED_READ_SUPPORTED */