1 /*- 2 * pngstest.c 3 * 4 * Copyright (c) 2013 John Cunningham Bowler 5 * 6 * Last changed in libpng 1.6.8 [December 19, 2013] 7 * 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 11 * 12 * Test for the PNG 'simplified' APIs. 13 */ 14 #define _ISOC90_SOURCE 1 15 #define MALLOC_CHECK_ 2/*glibc facility: turn on debugging*/ 16 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> 24 25 #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) 26 # include <config.h> 27 #endif 28 29 /* Define the following to use this test against your installed libpng, rather 30 * than the one being built here: 31 */ 32 #ifdef PNG_FREESTANDING_TESTS 33 # include <png.h> 34 #else 35 # include "../../png.h" 36 #endif 37 38 #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* Else nothing can be done */ 39 #include "../tools/sRGB.h" 40 41 /* KNOWN ISSUES 42 * 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. 47 */ 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. 53 */ 54 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 */ 64 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. 68 */ 69 static char tmpf[23] = "TMP"; 70 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". 76 */ 77 static void 78 make_random_bytes(png_uint_32* seed, void* pv, size_t size) 79 { 80 png_uint_32 u0 = seed[0], u1 = seed[1]; 81 png_bytep bytes = voidcast(png_bytep, pv); 82 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. 85 */ 86 size_t i; 87 for (i=0; i<size; ++i) 88 { 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; 96 } 97 98 seed[0] = u0; 99 seed[1] = u1; 100 } 101 102 static void 103 random_color(png_colorp color) 104 { 105 static png_uint_32 color_seed[2] = { 0x12345678, 0x9abcdef }; 106 make_random_bytes(color_seed, color, sizeof *color); 107 } 108 109 /* Math support - neither Cygwin nor Visual Studio have C99 support and we need 110 * a predictable rounding function, so make one here: 111 */ 112 static double 113 closestinteger(double x) 114 { 115 return floor(x + .5); 116 } 117 118 /* Cast support: remove GCC whines. */ 119 static png_byte 120 u8d(double d) 121 { 122 d = closestinteger(d); 123 return (png_byte)d; 124 } 125 126 static png_uint_16 127 u16d(double d) 128 { 129 d = closestinteger(d); 130 return (png_uint_16)d; 131 } 132 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. 135 */ 136 static double sRGB_to_d[256]; 137 static double g22_to_d[256]; 138 139 static void 140 init_sRGB_to_d(void) 141 { 142 int i; 143 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; 148 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; 153 } 154 155 static png_byte 156 sRGB(double linear /*range 0.0 .. 1.0*/) 157 { 158 return u8d(255 * sRGB_from_linear(linear)); 159 } 160 161 static png_byte 162 isRGB(int fixed_linear) 163 { 164 return sRGB(fixed_linear / 65535.); 165 } 166 167 #if 0 /* not used */ 168 static png_byte 169 unpremultiply(int component, int alpha) 170 { 171 if (alpha <= component) 172 return 255; /* Arbitrary, but consistent with the libpng code */ 173 174 else if (alpha >= 65535) 175 return isRGB(component); 176 177 else 178 return sRGB((double)component / alpha); 179 } 180 #endif 181 182 static png_uint_16 183 ilinear(int fixed_srgb) 184 { 185 return u16d(65535 * sRGB_to_d[fixed_srgb]); 186 } 187 188 static png_uint_16 189 ilineara(int fixed_srgb, int alpha) 190 { 191 return u16d((257 * alpha) * sRGB_to_d[fixed_srgb]); 192 } 193 194 static png_uint_16 195 ilinear_g22(int fixed_srgb) 196 { 197 return u16d(65535 * g22_to_d[fixed_srgb]); 198 } 199 200 #if ALLOW_UNUSED_GPC 201 static png_uint_16 202 ilineara_g22(int fixed_srgb, int alpha) 203 { 204 return u16d((257 * alpha) * g22_to_d[fixed_srgb]); 205 } 206 #endif 207 208 static double 209 YfromRGBint(int ir, int ig, int ib) 210 { 211 double r = ir; 212 double g = ig; 213 double b = ib; 214 return YfromRGB(r, g, b); 215 } 216 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. 220 */ 221 static int 222 power_law_error8(int value) 223 { 224 if (value > 0 && value < 255) 225 { 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))); 229 230 /* Always allow an extra 1 here for rounding errors */ 231 e = 1+floor(255 * e); 232 return (int)e; 233 } 234 235 return 0; 236 } 237 238 static int error_in_sRGB_roundtrip = 56; /* by experiment */ 239 static int 240 power_law_error16(int value) 241 { 242 if (value > 0 && value < 65535) 243 { 244 /* Round trip the value through an 8-bit representation but using 245 * non-matching to/from conversions. 246 */ 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))); 250 251 /* Always allow an extra 1 here for rounding errors */ 252 e = error_in_sRGB_roundtrip+floor(65535 * e); 253 return (int)e; 254 } 255 256 return 0; 257 } 258 259 static int 260 compare_8bit(int v1, int v2, int error_limit, int multiple_algorithms) 261 { 262 int e = abs(v1-v2); 263 int ev1, ev2; 264 265 if (e <= error_limit) 266 return 1; 267 268 if (!multiple_algorithms) 269 return 0; 270 271 ev1 = power_law_error8(v1); 272 if (e <= ev1) 273 return 1; 274 275 ev2 = power_law_error8(v2); 276 if (e <= ev2) 277 return 1; 278 279 return 0; 280 } 281 282 static int 283 compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) 284 { 285 int e = abs(v1-v2); 286 int ev1, ev2; 287 288 if (e <= error_limit) 289 return 1; 290 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.) 294 */ 295 if (!multiple_algorithms) 296 return 0; 297 298 ev1 = power_law_error16(v1); 299 if (e <= ev1) 300 return 1; 301 302 ev2 = power_law_error16(v2); 303 if (e <= ev2) 304 return 1; 305 306 return 0; 307 } 308 #endif /* unused */ 309 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 319 320 static void 321 print_opts(png_uint_32 opts) 322 { 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"); 341 } 342 343 #define FORMAT_NO_CHANGE 0x80000000 /* additional flag */ 344 345 /* A name table for all the formats - defines the format of the '+' arguments to 346 * pngstest. 347 */ 348 #define FORMAT_COUNT 64 349 #define FORMAT_MASK 0x3f 350 static PNG_CONST char * PNG_CONST format_names[FORMAT_COUNT] = 351 { 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", 360 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", 369 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", 378 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", 387 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", 396 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", 405 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", 414 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", 423 }; 424 425 /* Decode an argument to a format number. */ 426 static png_uint_32 427 formatof(const char *arg) 428 { 429 char *ep; 430 unsigned long format = strtoul(arg, &ep, 0); 431 432 if (ep > arg && *ep == 0 && format < FORMAT_COUNT) 433 return (png_uint_32)format; 434 435 else for (format=0; format < FORMAT_COUNT; ++format) 436 { 437 if (strcmp(format_names[format], arg) == 0) 438 return (png_uint_32)format; 439 } 440 441 fprintf(stderr, "pngstest: format name '%s' invalid\n", arg); 442 return FORMAT_COUNT; 443 } 444 445 /* Bitset/test functions for formats */ 446 #define FORMAT_SET_COUNT (FORMAT_COUNT / 32) 447 typedef struct 448 { 449 png_uint_32 bits[FORMAT_SET_COUNT]; 450 } 451 format_list; 452 453 static void format_init(format_list *pf) 454 { 455 int i; 456 for (i=0; i<FORMAT_SET_COUNT; ++i) 457 pf->bits[i] = 0; /* All off */ 458 } 459 460 #if 0 /* currently unused */ 461 static void format_clear(format_list *pf) 462 { 463 int i; 464 for (i=0; i<FORMAT_SET_COUNT; ++i) 465 pf->bits[i] = 0; 466 } 467 #endif 468 469 static int format_is_initial(format_list *pf) 470 { 471 int i; 472 for (i=0; i<FORMAT_SET_COUNT; ++i) 473 if (pf->bits[i] != 0) 474 return 0; 475 476 return 1; 477 } 478 479 static int format_set(format_list *pf, png_uint_32 format) 480 { 481 if (format < FORMAT_COUNT) 482 return pf->bits[format >> 5] |= ((png_uint_32)1) << (format & 31); 483 484 return 0; 485 } 486 487 #if 0 /* currently unused */ 488 static int format_unset(format_list *pf, png_uint_32 format) 489 { 490 if (format < FORMAT_COUNT) 491 return pf->bits[format >> 5] &= ~((png_uint_32)1) << (format & 31); 492 493 return 0; 494 } 495 #endif 496 497 static int format_isset(format_list *pf, png_uint_32 format) 498 { 499 return format < FORMAT_COUNT && 500 (pf->bits[format >> 5] & (((png_uint_32)1) << (format & 31))) != 0; 501 } 502 503 static void format_default(format_list *pf, int redundant) 504 { 505 if (redundant) 506 { 507 int i; 508 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; 512 } 513 514 else 515 { 516 png_uint_32 f; 517 518 for (f=0; f<FORMAT_COUNT; ++f) 519 { 520 /* Eliminate redundant and unsupported settings. */ 521 # ifdef PNG_FORMAT_BGR_SUPPORTED 522 /* BGR is meaningless if no color: */ 523 if ((f & PNG_FORMAT_FLAG_COLOR) == 0 && 524 (f & PNG_FORMAT_FLAG_BGR) != 0) 525 # else 526 if ((f & 0x10U/*HACK: fixed value*/) != 0) 527 # endif 528 continue; 529 530 /* AFIRST is meaningless if no alpha: */ 531 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 532 if ((f & PNG_FORMAT_FLAG_ALPHA) == 0 && 533 (f & PNG_FORMAT_FLAG_AFIRST) != 0) 534 # else 535 if ((f & 0x20U/*HACK: fixed value*/) != 0) 536 # endif 537 continue; 538 539 format_set(pf, f); 540 } 541 } 542 } 543 544 /* THE Image STRUCTURE */ 545 /* The super-class of a png_image, contains the decoded image plus the input 546 * data necessary to re-read the file with a different format. 547 */ 548 typedef struct 549 { 550 png_image image; 551 png_uint_32 opts; 552 const char *file_name; 553 int stride_extra; 554 FILE *input_file; 555 png_voidp input_memory; 556 png_size_t input_memory_size; 557 png_bytep buffer; 558 ptrdiff_t stride; 559 png_size_t bufsize; 560 png_size_t allocsize; 561 char tmpfile_name[32]; 562 png_uint_16 colormap[256*4]; 563 } 564 Image; 565 566 /* Initializer: also sets the permitted error limit for 16-bit operations. */ 567 static void 568 newimage(Image *image) 569 { 570 memset(image, 0, sizeof *image); 571 } 572 573 /* Reset the image to be read again - only needs to rewind the FILE* at present. 574 */ 575 static void 576 resetimage(Image *image) 577 { 578 if (image->input_file != NULL) 579 rewind(image->input_file); 580 } 581 582 /* Free the image buffer; the buffer is re-used on a re-read, this is just for 583 * cleanup. 584 */ 585 static void 586 freebuffer(Image *image) 587 { 588 if (image->buffer) free(image->buffer); 589 image->buffer = NULL; 590 image->bufsize = 0; 591 image->allocsize = 0; 592 } 593 594 /* Delete function; cleans out all the allocated data and the temporary file in 595 * the image. 596 */ 597 static void 598 freeimage(Image *image) 599 { 600 freebuffer(image); 601 png_image_free(&image->image); 602 603 if (image->input_file != NULL) 604 { 605 fclose(image->input_file); 606 image->input_file = NULL; 607 } 608 609 if (image->input_memory != NULL) 610 { 611 free(image->input_memory); 612 image->input_memory = NULL; 613 image->input_memory_size = 0; 614 } 615 616 if (image->tmpfile_name[0] != 0 && (image->opts & KEEP_TMPFILES) == 0) 617 { 618 remove(image->tmpfile_name); 619 image->tmpfile_name[0] = 0; 620 } 621 } 622 623 /* This is actually a re-initializer; allows an image structure to be re-used by 624 * freeing everything that relates to an old image. 625 */ 626 static void initimage(Image *image, png_uint_32 opts, const char *file_name, 627 int stride_extra) 628 { 629 freeimage(image); 630 memset(&image->image, 0, sizeof image->image); 631 image->opts = opts; 632 image->file_name = file_name; 633 image->stride_extra = stride_extra; 634 } 635 636 /* Make sure the image buffer is big enough; allows re-use of the buffer if the 637 * image is re-read. 638 */ 639 #define BUFFER_INIT8 73 640 static void 641 allocbuffer(Image *image) 642 { 643 png_size_t size = PNG_IMAGE_BUFFER_SIZE(image->image, image->stride); 644 645 if (size+32 > image->bufsize) 646 { 647 freebuffer(image); 648 image->buffer = voidcast(png_bytep, malloc(size+32)); 649 if (image->buffer == NULL) 650 { 651 fflush(stdout); 652 fprintf(stderr, 653 "simpletest: out of memory allocating %lu(+32) byte buffer\n", 654 (unsigned long)size); 655 exit(1); 656 } 657 image->bufsize = size+32; 658 } 659 660 memset(image->buffer, 95, image->bufsize); 661 memset(image->buffer+16, BUFFER_INIT8, size); 662 image->allocsize = size; 663 } 664 665 /* Make sure 16 bytes match the given byte. */ 666 static int 667 check16(png_const_bytep bp, int b) 668 { 669 int i = 16; 670 671 do 672 if (*bp != b) return 1; 673 while (--i); 674 675 return 0; 676 } 677 678 /* Check for overwrite in the image buffer. */ 679 static void 680 checkbuffer(Image *image, const char *arg) 681 { 682 if (check16(image->buffer, 95)) 683 { 684 fflush(stdout); 685 fprintf(stderr, "%s: overwrite at start of image buffer\n", arg); 686 exit(1); 687 } 688 689 if (check16(image->buffer+16+image->allocsize, 95)) 690 { 691 fflush(stdout); 692 fprintf(stderr, "%s: overwrite at end of image buffer\n", arg); 693 exit(1); 694 } 695 } 696 697 /* ERROR HANDLING */ 698 /* Log a terminal error, also frees the libpng part of the image if necessary. 699 */ 700 static int 701 logerror(Image *image, const char *a1, const char *a2, const char *a3) 702 { 703 fflush(stdout); 704 if (image->image.warning_or_error) 705 fprintf(stderr, "%s%s%s: %s\n", a1, a2, a3, image->image.message); 706 707 else 708 fprintf(stderr, "%s%s%s\n", a1, a2, a3); 709 710 if (image->image.opaque != NULL) 711 { 712 fprintf(stderr, "%s: image opaque pointer non-NULL on error\n", 713 image->file_name); 714 png_image_free(&image->image); 715 } 716 717 return 0; 718 } 719 720 /* Log an error and close a file (just a utility to do both things in one 721 * function call.) 722 */ 723 static int 724 logclose(Image *image, FILE *f, const char *name, const char *operation) 725 { 726 int e = errno; 727 728 fclose(f); 729 return logerror(image, name, operation, strerror(e)); 730 } 731 732 /* Make sure the png_image has been freed - validates that libpng is doing what 733 * the spec says and freeing the image. 734 */ 735 static int 736 checkopaque(Image *image) 737 { 738 if (image->image.opaque != NULL) 739 { 740 png_image_free(&image->image); 741 return logerror(image, image->file_name, ": opaque not NULL", ""); 742 } 743 744 else if (image->image.warning_or_error != 0 && (image->opts & STRICT) != 0) 745 return logerror(image, image->file_name, " --strict", ""); 746 747 else 748 return 1; 749 } 750 751 /* IMAGE COMPARISON/CHECKING */ 752 /* Compare the pixels of two images, which should be the same but aren't. The 753 * images must have been checked for a size match. 754 */ 755 typedef struct 756 { 757 /* The components, for grayscale images the gray value is in 'g' and if alpha 758 * is not present 'a' is set to 255 or 65535 according to format. 759 */ 760 int r, g, b, a; 761 } Pixel; 762 763 typedef struct 764 { 765 /* The background as the original sRGB 8-bit value converted to the final 766 * integer format and as a double precision linear value in the range 0..1 767 * for with partially transparent pixels. 768 */ 769 int ir, ig, ib; 770 double dr, dg, db; /* linear r,g,b scaled to 0..1 */ 771 } Background; 772 773 /* Basic image formats; control the data but not the layout thereof. */ 774 #define BASE_FORMATS\ 775 (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_LINEAR) 776 777 /* Read a Pixel from a buffer. The code below stores the correct routine for 778 * the format in a function pointer, these are the routines: 779 */ 780 static void 781 gp_g8(Pixel *p, png_const_voidp pb) 782 { 783 png_const_bytep pp = voidcast(png_const_bytep, pb); 784 785 p->r = p->g = p->b = pp[0]; 786 p->a = 255; 787 } 788 789 static void 790 gp_ga8(Pixel *p, png_const_voidp pb) 791 { 792 png_const_bytep pp = voidcast(png_const_bytep, pb); 793 794 p->r = p->g = p->b = pp[0]; 795 p->a = pp[1]; 796 } 797 798 #ifdef PNG_FORMAT_AFIRST_SUPPORTED 799 static void 800 gp_ag8(Pixel *p, png_const_voidp pb) 801 { 802 png_const_bytep pp = voidcast(png_const_bytep, pb); 803 804 p->r = p->g = p->b = pp[1]; 805 p->a = pp[0]; 806 } 807 #endif 808 809 static void 810 gp_rgb8(Pixel *p, png_const_voidp pb) 811 { 812 png_const_bytep pp = voidcast(png_const_bytep, pb); 813 814 p->r = pp[0]; 815 p->g = pp[1]; 816 p->b = pp[2]; 817 p->a = 255; 818 } 819 820 #ifdef PNG_FORMAT_BGR_SUPPORTED 821 static void 822 gp_bgr8(Pixel *p, png_const_voidp pb) 823 { 824 png_const_bytep pp = voidcast(png_const_bytep, pb); 825 826 p->r = pp[2]; 827 p->g = pp[1]; 828 p->b = pp[0]; 829 p->a = 255; 830 } 831 #endif 832 833 static void 834 gp_rgba8(Pixel *p, png_const_voidp pb) 835 { 836 png_const_bytep pp = voidcast(png_const_bytep, pb); 837 838 p->r = pp[0]; 839 p->g = pp[1]; 840 p->b = pp[2]; 841 p->a = pp[3]; 842 } 843 844 #ifdef PNG_FORMAT_BGR_SUPPORTED 845 static void 846 gp_bgra8(Pixel *p, png_const_voidp pb) 847 { 848 png_const_bytep pp = voidcast(png_const_bytep, pb); 849 850 p->r = pp[2]; 851 p->g = pp[1]; 852 p->b = pp[0]; 853 p->a = pp[3]; 854 } 855 #endif 856 857 #ifdef PNG_FORMAT_AFIRST_SUPPORTED 858 static void 859 gp_argb8(Pixel *p, png_const_voidp pb) 860 { 861 png_const_bytep pp = voidcast(png_const_bytep, pb); 862 863 p->r = pp[1]; 864 p->g = pp[2]; 865 p->b = pp[3]; 866 p->a = pp[0]; 867 } 868 #endif 869 870 #if defined(PNG_FORMAT_AFIRST_SUPPORTED) && defined(PNG_FORMAT_BGR_SUPPORTED) 871 static void 872 gp_abgr8(Pixel *p, png_const_voidp pb) 873 { 874 png_const_bytep pp = voidcast(png_const_bytep, pb); 875 876 p->r = pp[3]; 877 p->g = pp[2]; 878 p->b = pp[1]; 879 p->a = pp[0]; 880 } 881 #endif 882 883 static void 884 gp_g16(Pixel *p, png_const_voidp pb) 885 { 886 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 887 888 p->r = p->g = p->b = pp[0]; 889 p->a = 65535; 890 } 891 892 static void 893 gp_ga16(Pixel *p, png_const_voidp pb) 894 { 895 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 896 897 p->r = p->g = p->b = pp[0]; 898 p->a = pp[1]; 899 } 900 901 #ifdef PNG_FORMAT_AFIRST_SUPPORTED 902 static void 903 gp_ag16(Pixel *p, png_const_voidp pb) 904 { 905 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 906 907 p->r = p->g = p->b = pp[1]; 908 p->a = pp[0]; 909 } 910 #endif 911 912 static void 913 gp_rgb16(Pixel *p, png_const_voidp pb) 914 { 915 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 916 917 p->r = pp[0]; 918 p->g = pp[1]; 919 p->b = pp[2]; 920 p->a = 65535; 921 } 922 923 #ifdef PNG_FORMAT_BGR_SUPPORTED 924 static void 925 gp_bgr16(Pixel *p, png_const_voidp pb) 926 { 927 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 928 929 p->r = pp[2]; 930 p->g = pp[1]; 931 p->b = pp[0]; 932 p->a = 65535; 933 } 934 #endif 935 936 static void 937 gp_rgba16(Pixel *p, png_const_voidp pb) 938 { 939 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 940 941 p->r = pp[0]; 942 p->g = pp[1]; 943 p->b = pp[2]; 944 p->a = pp[3]; 945 } 946 947 #ifdef PNG_FORMAT_BGR_SUPPORTED 948 static void 949 gp_bgra16(Pixel *p, png_const_voidp pb) 950 { 951 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 952 953 p->r = pp[2]; 954 p->g = pp[1]; 955 p->b = pp[0]; 956 p->a = pp[3]; 957 } 958 #endif 959 960 #ifdef PNG_FORMAT_AFIRST_SUPPORTED 961 static void 962 gp_argb16(Pixel *p, png_const_voidp pb) 963 { 964 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 965 966 p->r = pp[1]; 967 p->g = pp[2]; 968 p->b = pp[3]; 969 p->a = pp[0]; 970 } 971 #endif 972 973 #if defined(PNG_FORMAT_AFIRST_SUPPORTED) && defined(PNG_FORMAT_BGR_SUPPORTED) 974 static void 975 gp_abgr16(Pixel *p, png_const_voidp pb) 976 { 977 png_const_uint_16p pp = voidcast(png_const_uint_16p, pb); 978 979 p->r = pp[3]; 980 p->g = pp[2]; 981 p->b = pp[1]; 982 p->a = pp[0]; 983 } 984 #endif 985 986 /* Given a format, return the correct one of the above functions. */ 987 static void (* 988 get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb) 989 { 990 /* The color-map flag is irrelevant here - the caller of the function 991 * returned must either pass the buffer or, for a color-mapped image, the 992 * correct entry in the color-map. 993 */ 994 if (format & PNG_FORMAT_FLAG_LINEAR) 995 { 996 if (format & PNG_FORMAT_FLAG_COLOR) 997 { 998 # ifdef PNG_FORMAT_BGR_SUPPORTED 999 if (format & PNG_FORMAT_FLAG_BGR) 1000 { 1001 if (format & PNG_FORMAT_FLAG_ALPHA) 1002 { 1003 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 1004 if (format & PNG_FORMAT_FLAG_AFIRST) 1005 return gp_abgr16; 1006 1007 else 1008 # endif 1009 return gp_bgra16; 1010 } 1011 1012 else 1013 return gp_bgr16; 1014 } 1015 1016 else 1017 # endif 1018 { 1019 if (format & PNG_FORMAT_FLAG_ALPHA) 1020 { 1021 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 1022 if (format & PNG_FORMAT_FLAG_AFIRST) 1023 return gp_argb16; 1024 1025 else 1026 # endif 1027 return gp_rgba16; 1028 } 1029 1030 else 1031 return gp_rgb16; 1032 } 1033 } 1034 1035 else 1036 { 1037 if (format & PNG_FORMAT_FLAG_ALPHA) 1038 { 1039 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 1040 if (format & PNG_FORMAT_FLAG_AFIRST) 1041 return gp_ag16; 1042 1043 else 1044 # endif 1045 return gp_ga16; 1046 } 1047 1048 else 1049 return gp_g16; 1050 } 1051 } 1052 1053 else 1054 { 1055 if (format & PNG_FORMAT_FLAG_COLOR) 1056 { 1057 # ifdef PNG_FORMAT_BGR_SUPPORTED 1058 if (format & PNG_FORMAT_FLAG_BGR) 1059 { 1060 if (format & PNG_FORMAT_FLAG_ALPHA) 1061 { 1062 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 1063 if (format & PNG_FORMAT_FLAG_AFIRST) 1064 return gp_abgr8; 1065 1066 else 1067 # endif 1068 return gp_bgra8; 1069 } 1070 1071 else 1072 return gp_bgr8; 1073 } 1074 1075 else 1076 # endif 1077 { 1078 if (format & PNG_FORMAT_FLAG_ALPHA) 1079 { 1080 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 1081 if (format & PNG_FORMAT_FLAG_AFIRST) 1082 return gp_argb8; 1083 1084 else 1085 # endif 1086 return gp_rgba8; 1087 } 1088 1089 else 1090 return gp_rgb8; 1091 } 1092 } 1093 1094 else 1095 { 1096 if (format & PNG_FORMAT_FLAG_ALPHA) 1097 { 1098 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 1099 if (format & PNG_FORMAT_FLAG_AFIRST) 1100 return gp_ag8; 1101 1102 else 1103 # endif 1104 return gp_ga8; 1105 } 1106 1107 else 1108 return gp_g8; 1109 } 1110 } 1111 } 1112 1113 /* Convertion between pixel formats. The code above effectively eliminates the 1114 * component ordering changes leaving three basic changes: 1115 * 1116 * 1) Remove an alpha channel by pre-multiplication or compositing on a 1117 * background color. (Adding an alpha channel is a no-op.) 1118 * 1119 * 2) Remove color by mapping to grayscale. (Grayscale to color is a no-op.) 1120 * 1121 * 3) Convert between 8-bit and 16-bit components. (Both directtions are 1122 * relevant.) 1123 * 1124 * This gives the following base format conversion matrix: 1125 * 1126 * OUT: ----- 8-bit ----- ----- 16-bit ----- 1127 * IN G GA RGB RGBA G GA RGB RGBA 1128 * 8 G . . . . lin lin lin lin 1129 * 8 GA bckg . bckc . pre' pre pre' pre 1130 * 8 RGB g8 g8 . . glin glin lin lin 1131 * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre 1132 * 16 G sRGB sRGB sRGB sRGB . . . . 1133 * 16 GA b16g unpg b16c unpc A . A . 1134 * 16 RGB sG sG sRGB sRGB g16 g16 . . 1135 * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . 1136 * 1137 * 8-bit to 8-bit: 1138 * bckg: composite on gray background 1139 * bckc: composite on color background 1140 * g8: convert sRGB components to sRGB grayscale 1141 * g8b: convert sRGB components to grayscale and composite on gray background 1142 * 1143 * 8-bit to 16-bit: 1144 * lin: make sRGB components linear, alpha := 65535 1145 * pre: make sRGB components linear and premultiply by alpha (scale alpha) 1146 * pre': as 'pre' but alpha := 65535 1147 * glin: make sRGB components linear, convert to grayscale, alpha := 65535 1148 * gpre: make sRGB components grayscale and linear and premultiply by alpha 1149 * gpr': as 'gpre' but alpha := 65535 1150 * 1151 * 16-bit to 8-bit: 1152 * sRGB: convert linear components to sRGB, alpha := 255 1153 * unpg: unpremultiply gray component and convert to sRGB (scale alpha) 1154 * unpc: unpremultiply color components and convert to sRGB (scale alpha) 1155 * b16g: composite linear onto gray background and convert the result to sRGB 1156 * b16c: composite linear onto color background and convert the result to sRGB 1157 * sG: convert linear RGB to sRGB grayscale 1158 * sGp: unpremultiply RGB then convert to sRGB grayscale 1159 * sCp: unpremultiply RGB then convert to sRGB 1160 * gb16: composite linear onto background and convert to sRGB grayscale 1161 * (order doesn't matter, the composite and grayscale operations permute) 1162 * cb16: composite linear onto background and convert to sRGB 1163 * 1164 * 16-bit to 16-bit: 1165 * A: set alpha to 65535 1166 * g16: convert linear RGB to linear grayscale (alpha := 65535) 1167 * g16': as 'g16' but alpha is unchanged 1168 */ 1169 /* Simple copy: */ 1170 static void 1171 gpc_noop(Pixel *out, const Pixel *in, const Background *back) 1172 { 1173 (void)back; 1174 out->r = in->r; 1175 out->g = in->g; 1176 out->b = in->b; 1177 out->a = in->a; 1178 } 1179 1180 #if ALLOW_UNUSED_GPC 1181 static void 1182 gpc_nop8(Pixel *out, const Pixel *in, const Background *back) 1183 { 1184 (void)back; 1185 if (in->a == 0) 1186 out->r = out->g = out->b = 255; 1187 1188 else 1189 { 1190 out->r = in->r; 1191 out->g = in->g; 1192 out->b = in->b; 1193 } 1194 1195 out->a = in->a; 1196 } 1197 #endif 1198 1199 #if ALLOW_UNUSED_GPC 1200 static void 1201 gpc_nop6(Pixel *out, const Pixel *in, const Background *back) 1202 { 1203 (void)back; 1204 if (in->a == 0) 1205 out->r = out->g = out->b = 65535; 1206 1207 else 1208 { 1209 out->r = in->r; 1210 out->g = in->g; 1211 out->b = in->b; 1212 } 1213 1214 out->a = in->a; 1215 } 1216 #endif 1217 1218 /* 8-bit to 8-bit conversions */ 1219 /* bckg: composite on gray background */ 1220 static void 1221 gpc_bckg(Pixel *out, const Pixel *in, const Background *back) 1222 { 1223 if (in->a <= 0) 1224 out->r = out->g = out->b = back->ig; 1225 1226 else if (in->a >= 255) 1227 out->r = out->g = out->b = in->g; 1228 1229 else 1230 { 1231 double a = in->a / 255.; 1232 1233 out->r = out->g = out->b = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); 1234 } 1235 1236 out->a = 255; 1237 } 1238 1239 /* bckc: composite on color background */ 1240 static void 1241 gpc_bckc(Pixel *out, const Pixel *in, const Background *back) 1242 { 1243 if (in->a <= 0) 1244 { 1245 out->r = back->ir; 1246 out->g = back->ig; 1247 out->b = back->ib; 1248 } 1249 1250 else if (in->a >= 255) 1251 { 1252 out->r = in->r; 1253 out->g = in->g; 1254 out->b = in->b; 1255 } 1256 1257 else 1258 { 1259 double a = in->a / 255.; 1260 1261 out->r = sRGB(sRGB_to_d[in->r] * a + back->dr * (1-a)); 1262 out->g = sRGB(sRGB_to_d[in->g] * a + back->dg * (1-a)); 1263 out->b = sRGB(sRGB_to_d[in->b] * a + back->db * (1-a)); 1264 } 1265 1266 out->a = 255; 1267 } 1268 1269 /* g8: convert sRGB components to sRGB grayscale */ 1270 static void 1271 gpc_g8(Pixel *out, const Pixel *in, const Background *back) 1272 { 1273 (void)back; 1274 1275 if (in->r == in->g && in->g == in->b) 1276 out->r = out->g = out->b = in->g; 1277 1278 else 1279 out->r = out->g = out->b = 1280 sRGB(YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); 1281 1282 out->a = in->a; 1283 } 1284 1285 /* g8b: convert sRGB components to grayscale and composite on gray background */ 1286 static void 1287 gpc_g8b(Pixel *out, const Pixel *in, const Background *back) 1288 { 1289 if (in->a <= 0) 1290 out->r = out->g = out->b = back->ig; 1291 1292 else if (in->a >= 255) 1293 { 1294 if (in->r == in->g && in->g == in->b) 1295 out->r = out->g = out->b = in->g; 1296 1297 else 1298 out->r = out->g = out->b = sRGB(YfromRGB( 1299 sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); 1300 } 1301 1302 else 1303 { 1304 double a = in->a/255.; 1305 1306 out->r = out->g = out->b = sRGB(a * YfromRGB(sRGB_to_d[in->r], 1307 sRGB_to_d[in->g], sRGB_to_d[in->b]) + back->dg * (1-a)); 1308 } 1309 1310 out->a = 255; 1311 } 1312 1313 /* 8-bit to 16-bit conversions */ 1314 /* lin: make sRGB components linear, alpha := 65535 */ 1315 static void 1316 gpc_lin(Pixel *out, const Pixel *in, const Background *back) 1317 { 1318 (void)back; 1319 1320 out->r = ilinear(in->r); 1321 1322 if (in->g == in->r) 1323 { 1324 out->g = out->r; 1325 1326 if (in->b == in->r) 1327 out->b = out->r; 1328 1329 else 1330 out->b = ilinear(in->b); 1331 } 1332 1333 else 1334 { 1335 out->g = ilinear(in->g); 1336 1337 if (in->b == in->r) 1338 out->b = out->r; 1339 1340 else if (in->b == in->g) 1341 out->b = out->g; 1342 1343 else 1344 out->b = ilinear(in->b); 1345 } 1346 1347 out->a = 65535; 1348 } 1349 1350 /* pre: make sRGB components linear and premultiply by alpha (scale alpha) */ 1351 static void 1352 gpc_pre(Pixel *out, const Pixel *in, const Background *back) 1353 { 1354 (void)back; 1355 1356 out->r = ilineara(in->r, in->a); 1357 1358 if (in->g == in->r) 1359 { 1360 out->g = out->r; 1361 1362 if (in->b == in->r) 1363 out->b = out->r; 1364 1365 else 1366 out->b = ilineara(in->b, in->a); 1367 } 1368 1369 else 1370 { 1371 out->g = ilineara(in->g, in->a); 1372 1373 if (in->b == in->r) 1374 out->b = out->r; 1375 1376 else if (in->b == in->g) 1377 out->b = out->g; 1378 1379 else 1380 out->b = ilineara(in->b, in->a); 1381 } 1382 1383 out->a = in->a * 257; 1384 } 1385 1386 /* pre': as 'pre' but alpha := 65535 */ 1387 static void 1388 gpc_preq(Pixel *out, const Pixel *in, const Background *back) 1389 { 1390 (void)back; 1391 1392 out->r = ilineara(in->r, in->a); 1393 1394 if (in->g == in->r) 1395 { 1396 out->g = out->r; 1397 1398 if (in->b == in->r) 1399 out->b = out->r; 1400 1401 else 1402 out->b = ilineara(in->b, in->a); 1403 } 1404 1405 else 1406 { 1407 out->g = ilineara(in->g, in->a); 1408 1409 if (in->b == in->r) 1410 out->b = out->r; 1411 1412 else if (in->b == in->g) 1413 out->b = out->g; 1414 1415 else 1416 out->b = ilineara(in->b, in->a); 1417 } 1418 1419 out->a = 65535; 1420 } 1421 1422 /* glin: make sRGB components linear, convert to grayscale, alpha := 65535 */ 1423 static void 1424 gpc_glin(Pixel *out, const Pixel *in, const Background *back) 1425 { 1426 (void)back; 1427 1428 if (in->r == in->g && in->g == in->b) 1429 out->r = out->g = out->b = ilinear(in->g); 1430 1431 else 1432 out->r = out->g = out->b = u16d(65535 * 1433 YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); 1434 1435 out->a = 65535; 1436 } 1437 1438 /* gpre: make sRGB components grayscale and linear and premultiply by alpha */ 1439 static void 1440 gpc_gpre(Pixel *out, const Pixel *in, const Background *back) 1441 { 1442 (void)back; 1443 1444 if (in->r == in->g && in->g == in->b) 1445 out->r = out->g = out->b = ilineara(in->g, in->a); 1446 1447 else 1448 out->r = out->g = out->b = u16d(in->a * 257 * 1449 YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); 1450 1451 out->a = 257 * in->a; 1452 } 1453 1454 /* gpr': as 'gpre' but alpha := 65535 */ 1455 static void 1456 gpc_gprq(Pixel *out, const Pixel *in, const Background *back) 1457 { 1458 (void)back; 1459 1460 if (in->r == in->g && in->g == in->b) 1461 out->r = out->g = out->b = ilineara(in->g, in->a); 1462 1463 else 1464 out->r = out->g = out->b = u16d(in->a * 257 * 1465 YfromRGB(sRGB_to_d[in->r], sRGB_to_d[in->g], sRGB_to_d[in->b])); 1466 1467 out->a = 65535; 1468 } 1469 1470 /* 8-bit to 16-bit conversions for gAMA 45455 encoded values */ 1471 /* Lin: make gAMA 45455 components linear, alpha := 65535 */ 1472 static void 1473 gpc_Lin(Pixel *out, const Pixel *in, const Background *back) 1474 { 1475 (void)back; 1476 1477 out->r = ilinear_g22(in->r); 1478 1479 if (in->g == in->r) 1480 { 1481 out->g = out->r; 1482 1483 if (in->b == in->r) 1484 out->b = out->r; 1485 1486 else 1487 out->b = ilinear_g22(in->b); 1488 } 1489 1490 else 1491 { 1492 out->g = ilinear_g22(in->g); 1493 1494 if (in->b == in->r) 1495 out->b = out->r; 1496 1497 else if (in->b == in->g) 1498 out->b = out->g; 1499 1500 else 1501 out->b = ilinear_g22(in->b); 1502 } 1503 1504 out->a = 65535; 1505 } 1506 1507 #if ALLOW_UNUSED_GPC 1508 /* Pre: make gAMA 45455 components linear and premultiply by alpha (scale alpha) 1509 */ 1510 static void 1511 gpc_Pre(Pixel *out, const Pixel *in, const Background *back) 1512 { 1513 (void)back; 1514 1515 out->r = ilineara_g22(in->r, in->a); 1516 1517 if (in->g == in->r) 1518 { 1519 out->g = out->r; 1520 1521 if (in->b == in->r) 1522 out->b = out->r; 1523 1524 else 1525 out->b = ilineara_g22(in->b, in->a); 1526 } 1527 1528 else 1529 { 1530 out->g = ilineara_g22(in->g, in->a); 1531 1532 if (in->b == in->r) 1533 out->b = out->r; 1534 1535 else if (in->b == in->g) 1536 out->b = out->g; 1537 1538 else 1539 out->b = ilineara_g22(in->b, in->a); 1540 } 1541 1542 out->a = in->a * 257; 1543 } 1544 #endif 1545 1546 #if ALLOW_UNUSED_GPC 1547 /* Pre': as 'Pre' but alpha := 65535 */ 1548 static void 1549 gpc_Preq(Pixel *out, const Pixel *in, const Background *back) 1550 { 1551 (void)back; 1552 1553 out->r = ilineara_g22(in->r, in->a); 1554 1555 if (in->g == in->r) 1556 { 1557 out->g = out->r; 1558 1559 if (in->b == in->r) 1560 out->b = out->r; 1561 1562 else 1563 out->b = ilineara_g22(in->b, in->a); 1564 } 1565 1566 else 1567 { 1568 out->g = ilineara_g22(in->g, in->a); 1569 1570 if (in->b == in->r) 1571 out->b = out->r; 1572 1573 else if (in->b == in->g) 1574 out->b = out->g; 1575 1576 else 1577 out->b = ilineara_g22(in->b, in->a); 1578 } 1579 1580 out->a = 65535; 1581 } 1582 #endif 1583 1584 #if ALLOW_UNUSED_GPC 1585 /* Glin: make gAMA 45455 components linear, convert to grayscale, alpha := 65535 1586 */ 1587 static void 1588 gpc_Glin(Pixel *out, const Pixel *in, const Background *back) 1589 { 1590 (void)back; 1591 1592 if (in->r == in->g && in->g == in->b) 1593 out->r = out->g = out->b = ilinear_g22(in->g); 1594 1595 else 1596 out->r = out->g = out->b = u16d(65535 * 1597 YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); 1598 1599 out->a = 65535; 1600 } 1601 #endif 1602 1603 #if ALLOW_UNUSED_GPC 1604 /* Gpre: make gAMA 45455 components grayscale and linear and premultiply by 1605 * alpha. 1606 */ 1607 static void 1608 gpc_Gpre(Pixel *out, const Pixel *in, const Background *back) 1609 { 1610 (void)back; 1611 1612 if (in->r == in->g && in->g == in->b) 1613 out->r = out->g = out->b = ilineara_g22(in->g, in->a); 1614 1615 else 1616 out->r = out->g = out->b = u16d(in->a * 257 * 1617 YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); 1618 1619 out->a = 257 * in->a; 1620 } 1621 #endif 1622 1623 #if ALLOW_UNUSED_GPC 1624 /* Gpr': as 'Gpre' but alpha := 65535 */ 1625 static void 1626 gpc_Gprq(Pixel *out, const Pixel *in, const Background *back) 1627 { 1628 (void)back; 1629 1630 if (in->r == in->g && in->g == in->b) 1631 out->r = out->g = out->b = ilineara_g22(in->g, in->a); 1632 1633 else 1634 out->r = out->g = out->b = u16d(in->a * 257 * 1635 YfromRGB(g22_to_d[in->r], g22_to_d[in->g], g22_to_d[in->b])); 1636 1637 out->a = 65535; 1638 } 1639 #endif 1640 1641 /* 16-bit to 8-bit conversions */ 1642 /* sRGB: convert linear components to sRGB, alpha := 255 */ 1643 static void 1644 gpc_sRGB(Pixel *out, const Pixel *in, const Background *back) 1645 { 1646 (void)back; 1647 1648 out->r = isRGB(in->r); 1649 1650 if (in->g == in->r) 1651 { 1652 out->g = out->r; 1653 1654 if (in->b == in->r) 1655 out->b = out->r; 1656 1657 else 1658 out->b = isRGB(in->b); 1659 } 1660 1661 else 1662 { 1663 out->g = isRGB(in->g); 1664 1665 if (in->b == in->r) 1666 out->b = out->r; 1667 1668 else if (in->b == in->g) 1669 out->b = out->g; 1670 1671 else 1672 out->b = isRGB(in->b); 1673 } 1674 1675 out->a = 255; 1676 } 1677 1678 /* unpg: unpremultiply gray component and convert to sRGB (scale alpha) */ 1679 static void 1680 gpc_unpg(Pixel *out, const Pixel *in, const Background *back) 1681 { 1682 (void)back; 1683 1684 if (in->a <= 128) 1685 { 1686 out->r = out->g = out->b = 255; 1687 out->a = 0; 1688 } 1689 1690 else 1691 { 1692 out->r = out->g = out->b = sRGB((double)in->g / in->a); 1693 out->a = u8d(in->a / 257.); 1694 } 1695 } 1696 1697 /* unpc: unpremultiply color components and convert to sRGB (scale alpha) */ 1698 static void 1699 gpc_unpc(Pixel *out, const Pixel *in, const Background *back) 1700 { 1701 (void)back; 1702 1703 if (in->a <= 128) 1704 { 1705 out->r = out->g = out->b = 255; 1706 out->a = 0; 1707 } 1708 1709 else 1710 { 1711 out->r = sRGB((double)in->r / in->a); 1712 out->g = sRGB((double)in->g / in->a); 1713 out->b = sRGB((double)in->b / in->a); 1714 out->a = u8d(in->a / 257.); 1715 } 1716 } 1717 1718 /* b16g: composite linear onto gray background and convert the result to sRGB */ 1719 static void 1720 gpc_b16g(Pixel *out, const Pixel *in, const Background *back) 1721 { 1722 if (in->a <= 0) 1723 out->r = out->g = out->b = back->ig; 1724 1725 else 1726 { 1727 double a = in->a/65535.; 1728 double a1 = 1-a; 1729 1730 a /= 65535; 1731 out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); 1732 } 1733 1734 out->a = 255; 1735 } 1736 1737 /* b16c: composite linear onto color background and convert the result to sRGB*/ 1738 static void 1739 gpc_b16c(Pixel *out, const Pixel *in, const Background *back) 1740 { 1741 if (in->a <= 0) 1742 { 1743 out->r = back->ir; 1744 out->g = back->ig; 1745 out->b = back->ib; 1746 } 1747 1748 else 1749 { 1750 double a = in->a/65535.; 1751 double a1 = 1-a; 1752 1753 a /= 65535; 1754 out->r = sRGB(in->r * a + back->dr * a1); 1755 out->g = sRGB(in->g * a + back->dg * a1); 1756 out->b = sRGB(in->b * a + back->db * a1); 1757 } 1758 1759 out->a = 255; 1760 } 1761 1762 /* sG: convert linear RGB to sRGB grayscale */ 1763 static void 1764 gpc_sG(Pixel *out, const Pixel *in, const Background *back) 1765 { 1766 (void)back; 1767 1768 out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/65535); 1769 out->a = 255; 1770 } 1771 1772 /* sGp: unpremultiply RGB then convert to sRGB grayscale */ 1773 static void 1774 gpc_sGp(Pixel *out, const Pixel *in, const Background *back) 1775 { 1776 (void)back; 1777 1778 if (in->a <= 128) 1779 { 1780 out->r = out->g = out->b = 255; 1781 out->a = 0; 1782 } 1783 1784 else 1785 { 1786 out->r = out->g = out->b = sRGB(YfromRGBint(in->r, in->g, in->b)/in->a); 1787 out->a = u8d(in->a / 257.); 1788 } 1789 } 1790 1791 /* sCp: unpremultiply RGB then convert to sRGB */ 1792 static void 1793 gpc_sCp(Pixel *out, const Pixel *in, const Background *back) 1794 { 1795 (void)back; 1796 1797 if (in->a <= 128) 1798 { 1799 out->r = out->g = out->b = 255; 1800 out->a = 0; 1801 } 1802 1803 else 1804 { 1805 out->r = sRGB((double)in->r / in->a); 1806 out->g = sRGB((double)in->g / in->a); 1807 out->b = sRGB((double)in->b / in->a); 1808 out->a = u8d(in->a / 257.); 1809 } 1810 } 1811 1812 /* gb16: composite linear onto background and convert to sRGB grayscale */ 1813 /* (order doesn't matter, the composite and grayscale operations permute) */ 1814 static void 1815 gpc_gb16(Pixel *out, const Pixel *in, const Background *back) 1816 { 1817 if (in->a <= 0) 1818 out->r = out->g = out->b = back->ig; 1819 1820 else if (in->a >= 65535) 1821 out->r = out->g = out->b = isRGB(in->g); 1822 1823 else 1824 { 1825 double a = in->a / 65535.; 1826 double a1 = 1-a; 1827 1828 a /= 65535; 1829 out->r = out->g = out->b = sRGB(in->g * a + back->dg * a1); 1830 } 1831 1832 out->a = 255; 1833 } 1834 1835 /* cb16: composite linear onto background and convert to sRGB */ 1836 static void 1837 gpc_cb16(Pixel *out, const Pixel *in, const Background *back) 1838 { 1839 if (in->a <= 0) 1840 { 1841 out->r = back->ir; 1842 out->g = back->ig; 1843 out->b = back->ib; 1844 } 1845 1846 else if (in->a >= 65535) 1847 { 1848 out->r = isRGB(in->r); 1849 out->g = isRGB(in->g); 1850 out->b = isRGB(in->b); 1851 } 1852 1853 else 1854 { 1855 double a = in->a / 65535.; 1856 double a1 = 1-a; 1857 1858 a /= 65535; 1859 out->r = sRGB(in->r * a + back->dr * a1); 1860 out->g = sRGB(in->g * a + back->dg * a1); 1861 out->b = sRGB(in->b * a + back->db * a1); 1862 } 1863 1864 out->a = 255; 1865 } 1866 1867 /* 16-bit to 16-bit conversions */ 1868 /* A: set alpha to 65535 */ 1869 static void 1870 gpc_A(Pixel *out, const Pixel *in, const Background *back) 1871 { 1872 (void)back; 1873 out->r = in->r; 1874 out->g = in->g; 1875 out->b = in->b; 1876 out->a = 65535; 1877 } 1878 1879 /* g16: convert linear RGB to linear grayscale (alpha := 65535) */ 1880 static void 1881 gpc_g16(Pixel *out, const Pixel *in, const Background *back) 1882 { 1883 (void)back; 1884 out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); 1885 out->a = 65535; 1886 } 1887 1888 /* g16': as 'g16' but alpha is unchanged */ 1889 static void 1890 gpc_g16q(Pixel *out, const Pixel *in, const Background *back) 1891 { 1892 (void)back; 1893 out->r = out->g = out->b = u16d(YfromRGBint(in->r, in->g, in->b)); 1894 out->a = in->a; 1895 } 1896 1897 #if ALLOW_UNUSED_GPC 1898 /* Unused functions (to hide them from GCC unused function warnings) */ 1899 void (* const gpc_unused[]) 1900 (Pixel *out, const Pixel *in, const Background *back) = 1901 { 1902 gpc_Pre, gpc_Preq, gpc_Glin, gpc_Gpre, gpc_Gprq, gpc_nop8, gpc_nop6 1903 }; 1904 #endif 1905 1906 /* OUT: ----- 8-bit ----- ----- 16-bit ----- 1907 * IN G GA RGB RGBA G GA RGB RGBA 1908 * 8 G . . . . lin lin lin lin 1909 * 8 GA bckg . bckc . pre' pre pre' pre 1910 * 8 RGB g8 g8 . . glin glin lin lin 1911 * 8 RGBA g8b g8 bckc . gpr' gpre pre' pre 1912 * 16 G sRGB sRGB sRGB sRGB . . . . 1913 * 16 GA b16g unpg b16c unpc A . A . 1914 * 16 RGB sG sG sRGB sRGB g16 g16 . . 1915 * 16 RGBA gb16 sGp cb16 sCp g16 g16' A . 1916 * 1917 * The matrix is held in an array indexed thus: 1918 * 1919 * gpc_fn[out_format & BASE_FORMATS][in_format & BASE_FORMATS]; 1920 */ 1921 /* This will produce a compile time error if the FORMAT_FLAG values don't 1922 * match the above matrix! 1923 */ 1924 #if PNG_FORMAT_FLAG_ALPHA == 1 && PNG_FORMAT_FLAG_COLOR == 2 &&\ 1925 PNG_FORMAT_FLAG_LINEAR == 4 1926 static void (* const gpc_fn[8/*in*/][8/*out*/]) 1927 (Pixel *out, const Pixel *in, const Background *back) = 1928 { 1929 /*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ 1930 {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_Lin, gpc_Lin, gpc_Lin, gpc_Lin }, 1931 {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, 1932 {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, 1933 {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, 1934 {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, 1935 {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, 1936 {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, 1937 {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} 1938 }; 1939 1940 /* The array is repeated for the cases where both the input and output are color 1941 * mapped because then different algorithms are used. 1942 */ 1943 static void (* const gpc_fn_colormapped[8/*in*/][8/*out*/]) 1944 (Pixel *out, const Pixel *in, const Background *back) = 1945 { 1946 /*out: G-8 GA-8 RGB-8 RGBA-8 G-16 GA-16 RGB-16 RGBA-16 */ 1947 {gpc_noop,gpc_noop,gpc_noop,gpc_noop, gpc_lin, gpc_lin, gpc_lin, gpc_lin }, 1948 {gpc_bckg,gpc_noop,gpc_bckc,gpc_noop, gpc_preq,gpc_pre, gpc_preq,gpc_pre }, 1949 {gpc_g8, gpc_g8, gpc_noop,gpc_noop, gpc_glin,gpc_glin,gpc_lin, gpc_lin }, 1950 {gpc_g8b, gpc_g8, gpc_bckc,gpc_noop, gpc_gprq,gpc_gpre,gpc_preq,gpc_pre }, 1951 {gpc_sRGB,gpc_sRGB,gpc_sRGB,gpc_sRGB, gpc_noop,gpc_noop,gpc_noop,gpc_noop}, 1952 {gpc_b16g,gpc_unpg,gpc_b16c,gpc_unpc, gpc_A, gpc_noop,gpc_A, gpc_noop}, 1953 {gpc_sG, gpc_sG, gpc_sRGB,gpc_sRGB, gpc_g16, gpc_g16, gpc_noop,gpc_noop}, 1954 {gpc_gb16,gpc_sGp, gpc_cb16,gpc_sCp, gpc_g16, gpc_g16q,gpc_A, gpc_noop} 1955 }; 1956 1957 /* The error arrays record the error in the same matrix; 64 entries, however 1958 * the different algorithms used in libpng for colormap and direct conversions 1959 * mean that four separate matrices are used (for each combination of 1960 * colormapped and direct.) 1961 * 1962 * In some cases the conversion between sRGB formats goes via a linear 1963 * intermediate; an sRGB to linear conversion (as above) is followed by a simple 1964 * linear to sRGB step with no other conversions. This is done by a separate 1965 * error array from an arbitrary 'in' format to one of the four basic outputs 1966 * (since final output is always sRGB not colormapped). 1967 * 1968 * These arrays may be modified if the --accumulate flag is set during the run; 1969 * then instead of logging errors they are simply added in. 1970 * 1971 * The three entries are currently for transparent, partially transparent and 1972 * opaque input pixel values. Notice that alpha should be exact in each case. 1973 * 1974 * Errors in alpha should only occur when converting from a direct format 1975 * to a colormapped format, when alpha is effectively smashed (so large 1976 * errors can occur.) There should be no error in the '0' and 'opaque' 1977 * values. The fourth entry in the array is used for the alpha error (and it 1978 * should always be zero for the 'via linear' case since this is never color 1979 * mapped.) 1980 * 1981 * Mapping to a colormap smashes the colors, it is necessary to have separate 1982 * values for these cases because they are much larger; it is very much 1983 * impossible to obtain a reasonable result, these are held in 1984 * gpc_error_to_colormap. 1985 */ 1986 #if PNG_FORMAT_FLAG_COLORMAP == 8 /* extra check also required */ 1987 /* START MACHINE GENERATED */ 1988 static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] = 1989 { 1990 { /* input: sRGB-gray */ 1991 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 1992 { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 0 }, { 0, 0, 372, 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: sRGB-gray+alpha */ 1996 { 0, 18, 0, 0 }, { 0, 0, 0, 0 }, { 0, 20, 0, 0 }, { 0, 0, 0, 0 }, 1997 { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, 1998 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 1999 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2000 }, { /* input: sRGB-rgb */ 2001 { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2002 { 0, 0, 893, 0 }, { 0, 0, 893, 0 }, { 0, 0, 811, 0 }, { 0, 0, 811, 0 }, 2003 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2004 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2005 }, { /* input: sRGB-rgb+alpha */ 2006 { 0, 4, 13, 0 }, { 0, 14, 13, 0 }, { 0, 19, 0, 0 }, { 0, 0, 0, 0 }, 2007 { 0, 832, 764, 0 }, { 0, 832, 764, 0 }, { 0, 897, 788, 0 }, { 0, 897, 788, 0 }, 2008 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2009 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2010 }, { /* input: linear-gray */ 2011 { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 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, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2015 }, { /* input: linear-gray+alpha */ 2016 { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, { 0, 74, 9, 0 }, { 0, 20, 9, 0 }, 2017 { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 1, 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, 0, 0 }, { 0, 0, 0, 0 } 2020 }, { /* input: linear-rgb */ 2021 { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, 2022 { 0, 0, 4, 0 }, { 0, 0, 4, 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, 0, 0, 0 } 2025 }, { /* input: linear-rgb+alpha */ 2026 { 0, 126, 143, 0 }, { 0, 9, 7, 0 }, { 0, 74, 9, 0 }, { 0, 16, 9, 0 }, 2027 { 0, 4, 4, 0 }, { 0, 5, 4, 0 }, { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, 2028 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2029 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2030 }, { /* input: color-mapped-sRGB-gray */ 2031 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2032 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2033 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2034 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2035 }, { /* input: color-mapped-sRGB-gray+alpha */ 2036 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2037 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2038 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2039 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2040 }, { /* input: color-mapped-sRGB-rgb */ 2041 { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 8, 0 }, { 0, 0, 8, 0 }, 2042 { 0, 0, 673, 0 }, { 0, 0, 673, 0 }, { 0, 0, 674, 0 }, { 0, 0, 674, 0 }, 2043 { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2044 { 0, 0, 460, 0 }, { 0, 0, 460, 0 }, { 0, 0, 263, 0 }, { 0, 0, 263, 0 } 2045 }, { /* input: color-mapped-sRGB-rgb+alpha */ 2046 { 0, 6, 8, 0 }, { 0, 7, 8, 0 }, { 0, 75, 8, 0 }, { 0, 9, 8, 0 }, 2047 { 0, 585, 427, 0 }, { 0, 585, 427, 0 }, { 0, 717, 409, 0 }, { 0, 717, 409, 0 }, 2048 { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, 2049 { 0, 13323, 460, 0 }, { 0, 334, 460, 0 }, { 0, 16480, 263, 0 }, { 0, 243, 263, 0 } 2050 }, { /* input: color-mapped-linear-gray */ 2051 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2052 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2053 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2054 { 0, 0, 282, 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 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2058 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2059 { 0, 0, 0, 0 }, { 0, 253, 282, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2060 }, { /* input: color-mapped-linear-rgb */ 2061 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2062 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2063 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2064 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 265, 0 }, { 0, 0, 0, 0 } 2065 }, { /* input: color-mapped-linear-rgb+alpha */ 2066 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2067 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2068 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 2069 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 243, 265, 0 } 2070 } 2071 }; 2072 static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] = 2073 { 2074 { /* input: sRGB-gray */ 2075 { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 }, { 0, 0, 7, 0 } 2076 }, { /* input: sRGB-gray+alpha */ 2077 { 0, 15, 15, 0 }, { 0, 186, 15, 0 }, { 0, 15, 15, 0 }, { 0, 186, 15, 0 } 2078 }, { /* input: sRGB-rgb */ 2079 { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 15, 0 }, { 0, 0, 15, 0 } 2080 }, { /* input: sRGB-rgb+alpha */ 2081 { 0, 12, 14, 0 }, { 0, 180, 14, 0 }, { 0, 14, 15, 0 }, { 0, 186, 15, 0 } 2082 }, { /* input: linear-gray */ 2083 { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } 2084 }, { /* input: linear-gray+alpha */ 2085 { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } 2086 }, { /* input: linear-rgb */ 2087 { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } 2088 }, { /* input: linear-rgb+alpha */ 2089 { 0, 1, 1, 0 }, { 0, 8, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 } 2090 }, { /* input: color-mapped-sRGB-gray */ 2091 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2092 }, { /* input: color-mapped-sRGB-gray+alpha */ 2093 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2094 }, { /* input: color-mapped-sRGB-rgb */ 2095 { 0, 0, 13, 0 }, { 0, 0, 13, 0 }, { 0, 0, 14, 0 }, { 0, 0, 14, 0 } 2096 }, { /* input: color-mapped-sRGB-rgb+alpha */ 2097 { 0, 4, 8, 0 }, { 0, 9, 8, 0 }, { 0, 8, 3, 0 }, { 0, 32, 3, 0 } 2098 }, { /* input: color-mapped-linear-gray */ 2099 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2100 }, { /* input: color-mapped-linear-gray+alpha */ 2101 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2102 }, { /* input: color-mapped-linear-rgb */ 2103 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2104 }, { /* input: color-mapped-linear-rgb+alpha */ 2105 { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } 2106 } 2107 }; 2108 static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] = 2109 { 2110 { /* input: sRGB-gray */ 2111 { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, { 0, 0, 9, 0 }, 2112 { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 }, { 0, 0, 560, 0 } 2113 }, { /* input: sRGB-gray+alpha */ 2114 { 0, 19, 2, 0 }, { 0, 255, 2, 25 }, { 0, 88, 2, 0 }, { 0, 255, 2, 25 }, 2115 { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 }, { 0, 1012, 745, 0 }, { 0, 16026, 745, 6425 } 2116 }, { /* input: sRGB-rgb */ 2117 { 0, 0, 19, 0 }, { 0, 0, 19, 0 }, { 0, 0, 25, 0 }, { 0, 0, 25, 0 }, 2118 { 0, 0, 937, 0 }, { 0, 0, 937, 0 }, { 0, 0, 13677, 0 }, { 0, 0, 13677, 0 } 2119 }, { /* input: sRGB-rgb+alpha */ 2120 { 0, 63, 77, 0 }, { 0, 255, 19, 25 }, { 0, 220, 25, 0 }, { 0, 255, 25, 67 }, 2121 { 0, 17534, 18491, 0 }, { 0, 15614, 2824, 6425 }, { 0, 14019, 13677, 0 }, { 0, 48573, 13677, 17219 } 2122 }, { /* input: linear-gray */ 2123 { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, 2124 { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 }, { 0, 0, 18817, 0 } 2125 }, { /* input: linear-gray+alpha */ 2126 { 0, 74, 74, 0 }, { 0, 255, 74, 25 }, { 0, 97, 74, 0 }, { 0, 255, 74, 25 }, 2127 { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 }, { 0, 18919, 18907, 0 }, { 0, 24549, 18907, 6552 } 2128 }, { /* input: linear-rgb */ 2129 { 0, 0, 73, 0 }, { 0, 0, 73, 0 }, { 0, 0, 98, 0 }, { 0, 0, 98, 0 }, 2130 { 0, 0, 18664, 0 }, { 0, 0, 18664, 0 }, { 0, 0, 24998, 0 }, { 0, 0, 24998, 0 } 2131 }, { /* input: linear-rgb+alpha */ 2132 { 0, 181, 196, 0 }, { 0, 255, 61, 25 }, { 206, 187, 98, 0 }, { 0, 255, 98, 67 }, 2133 { 0, 18141, 18137, 0 }, { 0, 17494, 17504, 6553 }, { 0, 24979, 24992, 0 }, { 0, 46509, 24992, 17347 } 2134 } 2135 }; 2136 /* END MACHINE GENERATED */ 2137 #endif /* COLORMAP flag check */ 2138 #endif /* flag checks */ 2139 2140 typedef struct 2141 { 2142 /* Basic pixel information: */ 2143 Image* in_image; /* Input image */ 2144 const Image* out_image; /* Output image */ 2145 2146 /* 'background' is the value passed to the gpc_ routines, it may be NULL if 2147 * it should not be used (*this* program has an error if it crashes as a 2148 * result!) 2149 */ 2150 Background background_color; 2151 const Background* background; 2152 2153 /* Precalculated values: */ 2154 int in_opaque; /* Value of input alpha that is opaque */ 2155 int is_palette; /* Sample values come from the palette */ 2156 int accumulate; /* Accumlate component errors (don't log) */ 2157 int output_8bit; /* Output is 8 bit (else 16 bit) */ 2158 2159 void (*in_gp)(Pixel*, png_const_voidp); 2160 void (*out_gp)(Pixel*, png_const_voidp); 2161 2162 void (*transform)(Pixel *out, const Pixel *in, const Background *back); 2163 /* A function to perform the required transform */ 2164 2165 void (*from_linear)(Pixel *out, const Pixel *in, const Background *back); 2166 /* For 'via_linear' transforms the final, from linear, step, else NULL */ 2167 2168 png_uint_16 error[4]; 2169 /* Three error values for transparent, partially transparent and opaque 2170 * input pixels (in turn). 2171 */ 2172 2173 png_uint_16 *error_ptr; 2174 /* Where these are stored in the static array (for 'accumulate') */ 2175 } 2176 Transform; 2177 2178 /* Return a 'transform' as above for the given format conversion. */ 2179 static void 2180 transform_from_formats(Transform *result, Image *in_image, 2181 const Image *out_image, png_const_colorp background, int via_linear) 2182 { 2183 png_uint_32 in_format, out_format; 2184 png_uint_32 in_base, out_base; 2185 2186 memset(result, 0, sizeof *result); 2187 2188 /* Store the original images for error messages */ 2189 result->in_image = in_image; 2190 result->out_image = out_image; 2191 2192 in_format = in_image->image.format; 2193 out_format = out_image->image.format; 2194 2195 if (in_format & PNG_FORMAT_FLAG_LINEAR) 2196 result->in_opaque = 65535; 2197 else 2198 result->in_opaque = 255; 2199 2200 result->output_8bit = (out_format & PNG_FORMAT_FLAG_LINEAR) == 0; 2201 2202 result->is_palette = 0; /* set by caller if required */ 2203 result->accumulate = (in_image->opts & ACCUMULATE) != 0; 2204 2205 /* The loaders (which need the ordering information) */ 2206 result->in_gp = get_pixel(in_format); 2207 result->out_gp = get_pixel(out_format); 2208 2209 /* Remove the ordering information: */ 2210 in_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; 2211 in_base = in_format & BASE_FORMATS; 2212 out_format &= BASE_FORMATS | PNG_FORMAT_FLAG_COLORMAP; 2213 out_base = out_format & BASE_FORMATS; 2214 2215 if (via_linear) 2216 { 2217 /* Check for an error in this program: */ 2218 if (out_format & (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLORMAP)) 2219 { 2220 fprintf(stderr, "internal transform via linear error 0x%x->0x%x\n", 2221 in_format, out_format); 2222 exit(1); 2223 } 2224 2225 result->transform = gpc_fn[in_base][out_base | PNG_FORMAT_FLAG_LINEAR]; 2226 result->from_linear = gpc_fn[out_base | PNG_FORMAT_FLAG_LINEAR][out_base]; 2227 result->error_ptr = gpc_error_via_linear[in_format][out_format]; 2228 } 2229 2230 else if (~in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) 2231 { 2232 /* The input is not colormapped but the output is, the errors will 2233 * typically be large (only the grayscale-no-alpha case permits preserving 2234 * even 8-bit values.) 2235 */ 2236 result->transform = gpc_fn[in_base][out_base]; 2237 result->from_linear = NULL; 2238 result->error_ptr = gpc_error_to_colormap[in_base][out_base]; 2239 } 2240 2241 else 2242 { 2243 /* The caller handles the colormap->pixel value conversion, so the 2244 * transform function just gets a pixel value, however because libpng 2245 * currently contains a different implementation for mapping a colormap if 2246 * both input and output are colormapped we need different conversion 2247 * functions to deal with errors in the libpng implementation. 2248 */ 2249 if (in_format & out_format & PNG_FORMAT_FLAG_COLORMAP) 2250 result->transform = gpc_fn_colormapped[in_base][out_base]; 2251 else 2252 result->transform = gpc_fn[in_base][out_base]; 2253 result->from_linear = NULL; 2254 result->error_ptr = gpc_error[in_format][out_format]; 2255 } 2256 2257 /* Follow the libpng simplified API rules to work out what to pass to the gpc 2258 * routines as a background value, if one is not required pass NULL so that 2259 * this program crashes in the even of a programming error. 2260 */ 2261 result->background = NULL; /* default: not required */ 2262 2263 /* Rule 1: background only need be supplied if alpha is to be removed */ 2264 if (in_format & ~out_format & PNG_FORMAT_FLAG_ALPHA) 2265 { 2266 /* The input value is 'NULL' to use the background and (otherwise) an sRGB 2267 * background color (to use a solid color). The code above uses a fixed 2268 * byte value, BUFFER_INIT8, for buffer even for 16-bit output. For 2269 * linear (16-bit) output the sRGB background color is ignored; the 2270 * composition is always on the background (so BUFFER_INIT8 * 257), except 2271 * that for the colormap (i.e. linear colormapped output) black is used. 2272 */ 2273 result->background = &result->background_color; 2274 2275 if (out_format & PNG_FORMAT_FLAG_LINEAR || via_linear) 2276 { 2277 if (out_format & PNG_FORMAT_FLAG_COLORMAP) 2278 { 2279 result->background_color.ir = 2280 result->background_color.ig = 2281 result->background_color.ib = 0; 2282 result->background_color.dr = 2283 result->background_color.dg = 2284 result->background_color.db = 0; 2285 } 2286 2287 else 2288 { 2289 result->background_color.ir = 2290 result->background_color.ig = 2291 result->background_color.ib = BUFFER_INIT8 * 257; 2292 result->background_color.dr = 2293 result->background_color.dg = 2294 result->background_color.db = 0; 2295 } 2296 } 2297 2298 else /* sRGB output */ 2299 { 2300 if (background != NULL) 2301 { 2302 if (out_format & PNG_FORMAT_FLAG_COLOR) 2303 { 2304 result->background_color.ir = background->red; 2305 result->background_color.ig = background->green; 2306 result->background_color.ib = background->blue; 2307 /* TODO: sometimes libpng uses the power law conversion here, how 2308 * to handle this? 2309 */ 2310 result->background_color.dr = sRGB_to_d[background->red]; 2311 result->background_color.dg = sRGB_to_d[background->green]; 2312 result->background_color.db = sRGB_to_d[background->blue]; 2313 } 2314 2315 else /* grayscale: libpng only looks at 'g' */ 2316 { 2317 result->background_color.ir = 2318 result->background_color.ig = 2319 result->background_color.ib = background->green; 2320 /* TODO: sometimes libpng uses the power law conversion here, how 2321 * to handle this? 2322 */ 2323 result->background_color.dr = 2324 result->background_color.dg = 2325 result->background_color.db = sRGB_to_d[background->green]; 2326 } 2327 } 2328 2329 else if ((out_format & PNG_FORMAT_FLAG_COLORMAP) == 0) 2330 { 2331 result->background_color.ir = 2332 result->background_color.ig = 2333 result->background_color.ib = BUFFER_INIT8; 2334 /* TODO: sometimes libpng uses the power law conversion here, how 2335 * to handle this? 2336 */ 2337 result->background_color.dr = 2338 result->background_color.dg = 2339 result->background_color.db = sRGB_to_d[BUFFER_INIT8]; 2340 } 2341 2342 /* Else the output is colormapped and a background color must be 2343 * provided; if pngstest crashes then that is a bug in this program 2344 * (though libpng should png_error as well.) 2345 */ 2346 else 2347 result->background = NULL; 2348 } 2349 } 2350 2351 if (result->background == NULL) 2352 { 2353 result->background_color.ir = 2354 result->background_color.ig = 2355 result->background_color.ib = -1; /* not used */ 2356 result->background_color.dr = 2357 result->background_color.dg = 2358 result->background_color.db = 1E30; /* not used */ 2359 } 2360 2361 2362 /* Copy the error values into the Transform: */ 2363 result->error[0] = result->error_ptr[0]; 2364 result->error[1] = result->error_ptr[1]; 2365 result->error[2] = result->error_ptr[2]; 2366 result->error[3] = result->error_ptr[3]; 2367 } 2368 2369 2370 /* Compare two pixels. 2371 * 2372 * OLD error values: 2373 static int error_to_linear = 811; * by experiment * 2374 static int error_to_linear_grayscale = 424; * by experiment * 2375 static int error_to_sRGB = 6; * by experiment * 2376 static int error_to_sRGB_grayscale = 17; * libpng error by calculation + 2377 2 by experiment * 2378 static int error_in_compose = 2; * by experiment * 2379 static int error_in_premultiply = 1; 2380 * 2381 * The following is *just* the result of a round trip from 8-bit sRGB to linear 2382 * then back to 8-bit sRGB when it is done by libpng. There are two problems: 2383 * 2384 * 1) libpng currently uses a 2.2 power law with no linear segment, this results 2385 * in instability in the low values and even with 16-bit precision sRGB(1) ends 2386 * up mapping to sRGB(0) as a result of rounding in the 16-bit representation. 2387 * This gives an error of 1 in the handling of value 1 only. 2388 * 2389 * 2) libpng currently uses an intermediate 8-bit linear value in gamma 2390 * correction of 8-bit values. This results in many more errors, the worse of 2391 * which is mapping sRGB(14) to sRGB(0). 2392 * 2393 * The general 'error_via_linear' is more complex because of pre-multiplication, 2394 * this compounds the 8-bit errors according to the alpha value of the pixel. 2395 * As a result 256 values are pre-calculated for error_via_linear. 2396 */ 2397 #if 0 2398 static int error_in_libpng_gamma; 2399 static int error_via_linear[256]; /* Indexed by 8-bit alpha */ 2400 2401 static void 2402 init_error_via_linear(void) 2403 { 2404 int alpha; 2405 2406 error_via_linear[0] = 255; /* transparent pixel */ 2407 2408 for (alpha=1; alpha<=255; ++alpha) 2409 { 2410 /* 16-bit values less than 128.5 get rounded to 8-bit 0 and so the worst 2411 * case error arises with 16-bit 128.5, work out what sRGB 2412 * (non-associated) value generates 128.5; any value less than this is 2413 * going to map to 0, so the worst error is floor(value). 2414 * 2415 * Note that errors are considerably higher (more than a factor of 2) 2416 * because libpng uses a simple power law for sRGB data at present. 2417 * 2418 * Add .1 for arithmetic errors inside libpng. 2419 */ 2420 double v = floor(255*pow(.5/*(128.5 * 255 / 65535)*/ / alpha, 1/2.2)+.1); 2421 2422 error_via_linear[alpha] = (int)v; 2423 } 2424 2425 /* This is actually 14.99, but, despite the closeness to 15, 14 seems to work 2426 * ok in this case. 2427 */ 2428 error_in_libpng_gamma = 14; 2429 } 2430 #endif 2431 2432 static void 2433 print_pixel(char string[64], const Pixel *pixel, png_uint_32 format) 2434 { 2435 switch (format & (PNG_FORMAT_FLAG_ALPHA|PNG_FORMAT_FLAG_COLOR)) 2436 { 2437 case 0: 2438 sprintf(string, "%s(%d)", format_names[format], pixel->g); 2439 break; 2440 2441 case PNG_FORMAT_FLAG_ALPHA: 2442 sprintf(string, "%s(%d,%d)", format_names[format], pixel->g, 2443 pixel->a); 2444 break; 2445 2446 case PNG_FORMAT_FLAG_COLOR: 2447 sprintf(string, "%s(%d,%d,%d)", format_names[format], 2448 pixel->r, pixel->g, pixel->b); 2449 break; 2450 2451 case PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA: 2452 sprintf(string, "%s(%d,%d,%d,%d)", format_names[format], 2453 pixel->r, pixel->g, pixel->b, pixel->a); 2454 break; 2455 2456 default: 2457 sprintf(string, "invalid-format"); 2458 break; 2459 } 2460 } 2461 2462 static int 2463 logpixel(const Transform *transform, png_uint_32 x, png_uint_32 y, 2464 const Pixel *in, const Pixel *calc, const Pixel *out, const char *reason) 2465 { 2466 const png_uint_32 in_format = transform->in_image->image.format; 2467 const png_uint_32 out_format = transform->out_image->image.format; 2468 2469 png_uint_32 back_format = out_format & ~PNG_FORMAT_FLAG_ALPHA; 2470 const char *via_linear = ""; 2471 2472 char pixel_in[64], pixel_calc[64], pixel_out[64], pixel_loc[64]; 2473 char background_info[100]; 2474 2475 print_pixel(pixel_in, in, in_format); 2476 print_pixel(pixel_calc, calc, out_format); 2477 print_pixel(pixel_out, out, out_format); 2478 2479 if (transform->is_palette) 2480 sprintf(pixel_loc, "palette: %lu", (unsigned long)y); 2481 else 2482 sprintf(pixel_loc, "%lu,%lu", (unsigned long)x, (unsigned long)y); 2483 2484 if (transform->from_linear != NULL) 2485 { 2486 via_linear = " (via linear)"; 2487 /* And as a result the *read* format which did any background processing 2488 * was itself linear, so the background color information is also 2489 * linear. 2490 */ 2491 back_format |= PNG_FORMAT_FLAG_LINEAR; 2492 } 2493 2494 if (transform->background != NULL) 2495 { 2496 Pixel back; 2497 char pixel_back[64]; 2498 2499 back.r = transform->background->ir; 2500 back.g = transform->background->ig; 2501 back.b = transform->background->ib; 2502 back.a = -1; /* not used */ 2503 2504 print_pixel(pixel_back, &back, back_format); 2505 sprintf(background_info, " on background %s", pixel_back); 2506 } 2507 2508 else 2509 background_info[0] = 0; 2510 2511 if (transform->in_image->file_name != transform->out_image->file_name) 2512 { 2513 char error_buffer[512]; 2514 sprintf(error_buffer, 2515 "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" 2516 "Use --preserve and examine: ", pixel_loc, reason, via_linear, 2517 pixel_in, background_info, pixel_out, pixel_calc); 2518 return logerror(transform->in_image, transform->in_image->file_name, 2519 error_buffer, transform->out_image->file_name); 2520 } 2521 2522 else 2523 { 2524 char error_buffer[512]; 2525 sprintf(error_buffer, 2526 "(%s) %s error%s:\n %s%s ->\n %s\n not: %s.\n" 2527 " The error happened when reading the original file with this format.", 2528 pixel_loc, reason, via_linear, pixel_in, background_info, pixel_out, 2529 pixel_calc); 2530 return logerror(transform->in_image, transform->in_image->file_name, 2531 error_buffer, ""); 2532 } 2533 } 2534 2535 static int 2536 cmppixel(Transform *transform, png_const_voidp in, png_const_voidp out, 2537 png_uint_32 x, png_uint_32 y/*or palette index*/) 2538 { 2539 int maxerr; 2540 png_const_charp errmsg; 2541 Pixel pixel_in, pixel_calc, pixel_out; 2542 2543 transform->in_gp(&pixel_in, in); 2544 2545 if (transform->from_linear == NULL) 2546 transform->transform(&pixel_calc, &pixel_in, transform->background); 2547 2548 else 2549 { 2550 transform->transform(&pixel_out, &pixel_in, transform->background); 2551 transform->from_linear(&pixel_calc, &pixel_out, NULL); 2552 } 2553 2554 transform->out_gp(&pixel_out, out); 2555 2556 /* Eliminate the case where the input and output values match exactly. */ 2557 if (pixel_calc.a == pixel_out.a && pixel_calc.r == pixel_out.r && 2558 pixel_calc.g == pixel_out.g && pixel_calc.b == pixel_out.b) 2559 return 1; 2560 2561 /* Eliminate the case where the output pixel is transparent and the output 2562 * is 8-bit - any component values are valid. Don't check the input alpha 2563 * here to also skip the 16-bit small alpha cases. 2564 */ 2565 if (transform->output_8bit && pixel_calc.a == 0 && pixel_out.a == 0) 2566 return 1; 2567 2568 /* Check for alpha errors first; an alpha error can damage the components too 2569 * so avoid spurious checks on components if one is found. 2570 */ 2571 errmsg = NULL; 2572 { 2573 int err_a = abs(pixel_calc.a-pixel_out.a); 2574 2575 if (err_a > transform->error[3]) 2576 { 2577 /* If accumulating check the components too */ 2578 if (transform->accumulate) 2579 transform->error[3] = (png_uint_16)err_a; 2580 2581 else 2582 errmsg = "alpha"; 2583 } 2584 } 2585 2586 /* Now if *either* of the output alphas are 0 but alpha is within tolerance 2587 * eliminate the 8-bit component comparison. 2588 */ 2589 if (errmsg == NULL && transform->output_8bit && 2590 (pixel_calc.a == 0 || pixel_out.a == 0)) 2591 return 1; 2592 2593 if (errmsg == NULL) /* else just signal an alpha error */ 2594 { 2595 int err_r = abs(pixel_calc.r - pixel_out.r); 2596 int err_g = abs(pixel_calc.g - pixel_out.g); 2597 int err_b = abs(pixel_calc.b - pixel_out.b); 2598 int limit; 2599 2600 if ((err_r | err_g | err_b) == 0) 2601 return 1; /* exact match */ 2602 2603 /* Mismatch on a component, check the input alpha */ 2604 if (pixel_in.a >= transform->in_opaque) 2605 { 2606 errmsg = "opaque component"; 2607 limit = 2; /* opaque */ 2608 } 2609 2610 else if (pixel_in.a > 0) 2611 { 2612 errmsg = "alpha component"; 2613 limit = 1; /* partially transparent */ 2614 } 2615 2616 else 2617 { 2618 errmsg = "transparent component (background)"; 2619 limit = 0; /* transparent */ 2620 } 2621 2622 maxerr = err_r; 2623 if (maxerr < err_g) maxerr = err_g; 2624 if (maxerr < err_b) maxerr = err_b; 2625 2626 if (maxerr <= transform->error[limit]) 2627 return 1; /* within the error limits */ 2628 2629 /* Handle a component mis-match; log it, just return an error code, or 2630 * accumulate it. 2631 */ 2632 if (transform->accumulate) 2633 { 2634 transform->error[limit] = (png_uint_16)maxerr; 2635 return 1; /* to cause the caller to keep going */ 2636 } 2637 } 2638 2639 /* Failure to match and not accumulating, so the error must be logged. */ 2640 return logpixel(transform, x, y, &pixel_in, &pixel_calc, &pixel_out, errmsg); 2641 } 2642 2643 static png_byte 2644 component_loc(png_byte loc[4], png_uint_32 format) 2645 { 2646 /* Given a format return the number of channels and the location of 2647 * each channel. 2648 * 2649 * The mask 'loc' contains the component offset of the channels in the 2650 * following order. Note that if 'format' is grayscale the entries 1-3 must 2651 * all contain the location of the gray channel. 2652 * 2653 * 0: alpha 2654 * 1: red or gray 2655 * 2: green or gray 2656 * 3: blue or gray 2657 */ 2658 png_byte channels; 2659 2660 if (format & PNG_FORMAT_FLAG_COLOR) 2661 { 2662 channels = 3; 2663 2664 loc[2] = 1; 2665 2666 # ifdef PNG_FORMAT_BGR_SUPPORTED 2667 if (format & PNG_FORMAT_FLAG_BGR) 2668 { 2669 loc[1] = 2; 2670 loc[3] = 0; 2671 } 2672 2673 else 2674 # endif 2675 { 2676 loc[1] = 0; 2677 loc[3] = 2; 2678 } 2679 } 2680 2681 else 2682 { 2683 channels = 1; 2684 loc[1] = loc[2] = loc[3] = 0; 2685 } 2686 2687 if (format & PNG_FORMAT_FLAG_ALPHA) 2688 { 2689 # ifdef PNG_FORMAT_AFIRST_SUPPORTED 2690 if (format & PNG_FORMAT_FLAG_AFIRST) 2691 { 2692 loc[0] = 0; 2693 ++loc[1]; 2694 ++loc[2]; 2695 ++loc[3]; 2696 } 2697 2698 else 2699 # endif 2700 loc[0] = channels; 2701 2702 ++channels; 2703 } 2704 2705 else 2706 loc[0] = 4; /* not present */ 2707 2708 return channels; 2709 } 2710 2711 /* Compare two images, the original 'a', which was written out then read back in 2712 * to * give image 'b'. The formats may have been changed. 2713 */ 2714 static int 2715 compare_two_images(Image *a, Image *b, int via_linear, 2716 png_const_colorp background) 2717 { 2718 ptrdiff_t stridea = a->stride; 2719 ptrdiff_t strideb = b->stride; 2720 png_const_bytep rowa = a->buffer+16; 2721 png_const_bytep rowb = b->buffer+16; 2722 const png_uint_32 width = a->image.width; 2723 const png_uint_32 height = a->image.height; 2724 const png_uint_32 formata = a->image.format; 2725 const png_uint_32 formatb = b->image.format; 2726 const unsigned int a_sample = PNG_IMAGE_SAMPLE_SIZE(formata); 2727 const unsigned int b_sample = PNG_IMAGE_SAMPLE_SIZE(formatb); 2728 int alpha_added, alpha_removed; 2729 int bchannels; 2730 int btoa[4]; 2731 png_uint_32 y; 2732 Transform tr; 2733 2734 /* This should never happen: */ 2735 if (width != b->image.width || height != b->image.height) 2736 return logerror(a, a->file_name, ": width x height changed: ", 2737 b->file_name); 2738 2739 /* Set up the background and the transform */ 2740 transform_from_formats(&tr, a, b, background, via_linear); 2741 2742 /* Find the first row and inter-row space. */ 2743 if (!(formata & PNG_FORMAT_FLAG_COLORMAP) && 2744 (formata & PNG_FORMAT_FLAG_LINEAR)) 2745 stridea *= 2; 2746 2747 if (!(formatb & PNG_FORMAT_FLAG_COLORMAP) && 2748 (formatb & PNG_FORMAT_FLAG_LINEAR)) 2749 strideb *= 2; 2750 2751 if (stridea < 0) rowa += (height-1) * (-stridea); 2752 if (strideb < 0) rowb += (height-1) * (-strideb); 2753 2754 /* First shortcut the two colormap case by comparing the image data; if it 2755 * matches then we expect the colormaps to match, although this is not 2756 * absolutely necessary for an image match. If the colormaps fail to match 2757 * then there is a problem in libpng. 2758 */ 2759 if (formata & formatb & PNG_FORMAT_FLAG_COLORMAP) 2760 { 2761 /* Only check colormap entries that actually exist; */ 2762 png_const_bytep ppa, ppb; 2763 int match; 2764 png_byte in_use[256], amax = 0, bmax = 0; 2765 2766 memset(in_use, 0, sizeof in_use); 2767 2768 ppa = rowa; 2769 ppb = rowb; 2770 2771 /* Do this the slow way to accumulate the 'in_use' flags, don't break out 2772 * of the loop until the end; this validates the color-mapped data to 2773 * ensure all pixels are valid color-map indexes. 2774 */ 2775 for (y=0, match=1; y<height && match; ++y, ppa += stridea, ppb += strideb) 2776 { 2777 png_uint_32 x; 2778 2779 for (x=0; x<width; ++x) 2780 { 2781 png_byte bval = ppb[x]; 2782 png_byte aval = ppa[x]; 2783 2784 if (bval > bmax) 2785 bmax = bval; 2786 2787 if (bval != aval) 2788 match = 0; 2789 2790 in_use[aval] = 1; 2791 if (aval > amax) 2792 amax = aval; 2793 } 2794 } 2795 2796 /* If the buffers match then the colormaps must too. */ 2797 if (match) 2798 { 2799 /* Do the color-maps match, entry by entry? Only check the 'in_use' 2800 * entries. An error here should be logged as a color-map error. 2801 */ 2802 png_const_bytep a_cmap = (png_const_bytep)a->colormap; 2803 png_const_bytep b_cmap = (png_const_bytep)b->colormap; 2804 int result = 1; /* match by default */ 2805 2806 /* This is used in logpixel to get the error message correct. */ 2807 tr.is_palette = 1; 2808 2809 for (y=0; y<256; ++y, a_cmap += a_sample, b_cmap += b_sample) 2810 if (in_use[y]) 2811 { 2812 /* The colormap entries should be valid, but because libpng doesn't 2813 * do any checking at present the original image may contain invalid 2814 * pixel values. These cause an error here (at present) unless 2815 * accumulating errors in which case the program just ignores them. 2816 */ 2817 if (y >= a->image.colormap_entries) 2818 { 2819 if ((a->opts & ACCUMULATE) == 0) 2820 { 2821 char pindex[9]; 2822 sprintf(pindex, "%lu[%lu]", (unsigned long)y, 2823 (unsigned long)a->image.colormap_entries); 2824 logerror(a, a->file_name, ": bad pixel index: ", pindex); 2825 } 2826 result = 0; 2827 } 2828 2829 else if (y >= b->image.colormap_entries) 2830 { 2831 if ((a->opts & ACCUMULATE) == 0) 2832 { 2833 char pindex[9]; 2834 sprintf(pindex, "%lu[%lu]", (unsigned long)y, 2835 (unsigned long)b->image.colormap_entries); 2836 logerror(b, b->file_name, ": bad pixel index: ", pindex); 2837 } 2838 result = 0; 2839 } 2840 2841 /* All the mismatches are logged here; there can only be 256! */ 2842 else if (!cmppixel(&tr, a_cmap, b_cmap, 0, y)) 2843 result = 0; 2844 } 2845 2846 /* If reqested copy the error values back from the Transform. */ 2847 if (a->opts & ACCUMULATE) 2848 { 2849 tr.error_ptr[0] = tr.error[0]; 2850 tr.error_ptr[1] = tr.error[1]; 2851 tr.error_ptr[2] = tr.error[2]; 2852 tr.error_ptr[3] = tr.error[3]; 2853 result = 1; /* force a continue */ 2854 } 2855 2856 return result; 2857 } 2858 2859 /* else the image buffers don't match pixel-wise so compare sample values 2860 * instead, but first validate that the pixel indexes are in range (but 2861 * only if not accumulating, when the error is ignored.) 2862 */ 2863 else if ((a->opts & ACCUMULATE) == 0) 2864 { 2865 /* Check the original image first, 2866 * TODO: deal with input images with bad pixel values? 2867 */ 2868 if (amax >= a->image.colormap_entries) 2869 { 2870 char pindex[9]; 2871 sprintf(pindex, "%d[%lu]", amax, 2872 (unsigned long)a->image.colormap_entries); 2873 return logerror(a, a->file_name, ": bad pixel index: ", pindex); 2874 } 2875 2876 else if (bmax >= b->image.colormap_entries) 2877 { 2878 char pindex[9]; 2879 sprintf(pindex, "%d[%lu]", bmax, 2880 (unsigned long)b->image.colormap_entries); 2881 return logerror(b, b->file_name, ": bad pixel index: ", pindex); 2882 } 2883 } 2884 } 2885 2886 /* We can directly compare pixel values without the need to use the read 2887 * or transform support (i.e. a memory compare) if: 2888 * 2889 * 1) The bit depth has not changed. 2890 * 2) RGB to grayscale has not been done (the reverse is ok; we just compare 2891 * the three RGB values to the original grayscale.) 2892 * 3) An alpha channel has not been removed from an 8-bit format, or the 2893 * 8-bit alpha value of the pixel was 255 (opaque). 2894 * 2895 * If an alpha channel has been *added* then it must have the relevant opaque 2896 * value (255 or 65535). 2897 * 2898 * The fist two the tests (in the order given above) (using the boolean 2899 * equivalence !a && !b == !(a || b)) 2900 */ 2901 if (!(((formata ^ formatb) & PNG_FORMAT_FLAG_LINEAR) | 2902 (formata & (formatb ^ PNG_FORMAT_FLAG_COLOR) & PNG_FORMAT_FLAG_COLOR))) 2903 { 2904 /* Was an alpha channel changed? */ 2905 const png_uint_32 alpha_changed = (formata ^ formatb) & 2906 PNG_FORMAT_FLAG_ALPHA; 2907 2908 /* Was an alpha channel removed? (The third test.) If so the direct 2909 * comparison is only possible if the input alpha is opaque. 2910 */ 2911 alpha_removed = (formata & alpha_changed) != 0; 2912 2913 /* Was an alpha channel added? */ 2914 alpha_added = (formatb & alpha_changed) != 0; 2915 2916 /* The channels may have been moved between input and output, this finds 2917 * out how, recording the result in the btoa array, which says where in 2918 * 'a' to find each channel of 'b'. If alpha was added then btoa[alpha] 2919 * ends up as 4 (and is not used.) 2920 */ 2921 { 2922 int i; 2923 png_byte aloc[4]; 2924 png_byte bloc[4]; 2925 2926 /* The following are used only if the formats match, except that 2927 * 'bchannels' is a flag for matching formats. btoa[x] says, for each 2928 * channel in b, where to find the corresponding value in a, for the 2929 * bchannels. achannels may be different for a gray to rgb transform 2930 * (a will be 1 or 2, b will be 3 or 4 channels.) 2931 */ 2932 (void)component_loc(aloc, formata); 2933 bchannels = component_loc(bloc, formatb); 2934 2935 /* Hence the btoa array. */ 2936 for (i=0; i<4; ++i) if (bloc[i] < 4) 2937 btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */ 2938 2939 if (alpha_added) 2940 alpha_added = bloc[0]; /* location of alpha channel in image b */ 2941 2942 else 2943 alpha_added = 4; /* Won't match an image b channel */ 2944 2945 if (alpha_removed) 2946 alpha_removed = aloc[0]; /* location of alpha channel in image a */ 2947 2948 else 2949 alpha_removed = 4; 2950 } 2951 } 2952 2953 else 2954 { 2955 /* Direct compare is not possible, cancel out all the corresponding local 2956 * variables. 2957 */ 2958 bchannels = 0; 2959 alpha_removed = alpha_added = 4; 2960 btoa[3] = btoa[2] = btoa[1] = btoa[0] = 4; /* 4 == not present */ 2961 } 2962 2963 for (y=0; y<height; ++y, rowa += stridea, rowb += strideb) 2964 { 2965 png_const_bytep ppa, ppb; 2966 png_uint_32 x; 2967 2968 for (x=0, ppa=rowa, ppb=rowb; x<width; ++x) 2969 { 2970 png_const_bytep psa, psb; 2971 2972 if (formata & PNG_FORMAT_FLAG_COLORMAP) 2973 psa = (png_const_bytep)a->colormap + a_sample * *ppa++; 2974 else 2975 psa = ppa, ppa += a_sample; 2976 2977 if (formatb & PNG_FORMAT_FLAG_COLORMAP) 2978 psb = (png_const_bytep)b->colormap + b_sample * *ppb++; 2979 else 2980 psb = ppb, ppb += b_sample; 2981 2982 /* Do the fast test if possible. */ 2983 if (bchannels) 2984 { 2985 /* Check each 'b' channel against either the corresponding 'a' 2986 * channel or the opaque alpha value, as appropriate. If 2987 * alpha_removed value is set (not 4) then also do this only if the 2988 * 'a' alpha channel (alpha_removed) is opaque; only relevant for 2989 * the 8-bit case. 2990 */ 2991 if (formatb & PNG_FORMAT_FLAG_LINEAR) /* 16-bit checks */ 2992 { 2993 png_const_uint_16p pua = aligncastconst(png_const_uint_16p, psa); 2994 png_const_uint_16p pub = aligncastconst(png_const_uint_16p, psb); 2995 2996 switch (bchannels) 2997 { 2998 case 4: 2999 if (pua[btoa[3]] != pub[3]) break; 3000 case 3: 3001 if (pua[btoa[2]] != pub[2]) break; 3002 case 2: 3003 if (pua[btoa[1]] != pub[1]) break; 3004 case 1: 3005 if (pua[btoa[0]] != pub[0]) break; 3006 if (alpha_added != 4 && pub[alpha_added] != 65535) break; 3007 continue; /* x loop */ 3008 default: 3009 break; /* impossible */ 3010 } 3011 } 3012 3013 else if (alpha_removed == 4 || psa[alpha_removed] == 255) 3014 { 3015 switch (bchannels) 3016 { 3017 case 4: 3018 if (psa[btoa[3]] != psb[3]) break; 3019 case 3: 3020 if (psa[btoa[2]] != psb[2]) break; 3021 case 2: 3022 if (psa[btoa[1]] != psb[1]) break; 3023 case 1: 3024 if (psa[btoa[0]] != psb[0]) break; 3025 if (alpha_added != 4 && psb[alpha_added] != 255) break; 3026 continue; /* x loop */ 3027 default: 3028 break; /* impossible */ 3029 } 3030 } 3031 } 3032 3033 /* If we get to here the fast match failed; do the slow match for this 3034 * pixel. 3035 */ 3036 if (!cmppixel(&tr, psa, psb, x, y) && (a->opts & KEEP_GOING) == 0) 3037 return 0; /* error case */ 3038 } 3039 } 3040 3041 /* If reqested copy the error values back from the Transform. */ 3042 if (a->opts & ACCUMULATE) 3043 { 3044 tr.error_ptr[0] = tr.error[0]; 3045 tr.error_ptr[1] = tr.error[1]; 3046 tr.error_ptr[2] = tr.error[2]; 3047 tr.error_ptr[3] = tr.error[3]; 3048 } 3049 3050 return 1; 3051 } 3052 3053 /* Read the file; how the read gets done depends on which of input_file and 3054 * input_memory have been set. 3055 */ 3056 static int 3057 read_file(Image *image, png_uint_32 format, png_const_colorp background) 3058 { 3059 memset(&image->image, 0, sizeof image->image); 3060 image->image.version = PNG_IMAGE_VERSION; 3061 3062 if (image->input_memory != NULL) 3063 { 3064 if (!png_image_begin_read_from_memory(&image->image, image->input_memory, 3065 image->input_memory_size)) 3066 return logerror(image, "memory init: ", image->file_name, ""); 3067 } 3068 3069 # ifdef PNG_STDIO_SUPPORTED 3070 else if (image->input_file != NULL) 3071 { 3072 if (!png_image_begin_read_from_stdio(&image->image, image->input_file)) 3073 return logerror(image, "stdio init: ", image->file_name, ""); 3074 } 3075 3076 else 3077 { 3078 if (!png_image_begin_read_from_file(&image->image, image->file_name)) 3079 return logerror(image, "file init: ", image->file_name, ""); 3080 } 3081 # else 3082 else 3083 { 3084 return logerror(image, "unsupported file/stdio init: ", 3085 image->file_name, ""); 3086 } 3087 # endif 3088 3089 /* This must be set after the begin_read call: */ 3090 if (image->opts & sRGB_16BIT) 3091 image->image.flags |= PNG_IMAGE_FLAG_16BIT_sRGB; 3092 3093 /* Have an initialized image with all the data we need plus, maybe, an 3094 * allocated file (myfile) or buffer (mybuffer) that need to be freed. 3095 */ 3096 { 3097 int result; 3098 png_uint_32 image_format; 3099 3100 /* Print both original and output formats. */ 3101 image_format = image->image.format; 3102 3103 if (image->opts & VERBOSE) 3104 { 3105 printf("%s %lu x %lu %s -> %s", image->file_name, 3106 (unsigned long)image->image.width, 3107 (unsigned long)image->image.height, 3108 format_names[image_format & FORMAT_MASK], 3109 (format & FORMAT_NO_CHANGE) != 0 || image->image.format == format 3110 ? "no change" : format_names[format & FORMAT_MASK]); 3111 3112 if (background != NULL) 3113 printf(" background(%d,%d,%d)\n", background->red, 3114 background->green, background->blue); 3115 else 3116 printf("\n"); 3117 3118 fflush(stdout); 3119 } 3120 3121 /* 'NO_CHANGE' combined with the color-map flag forces the base format 3122 * flags to be set on read to ensure that the original representation is 3123 * not lost in the pass through a colormap format. 3124 */ 3125 if ((format & FORMAT_NO_CHANGE) != 0) 3126 { 3127 if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && 3128 (image_format & PNG_FORMAT_FLAG_COLORMAP) != 0) 3129 format = (image_format & ~BASE_FORMATS) | (format & BASE_FORMATS); 3130 3131 else 3132 format = image_format; 3133 } 3134 3135 image->image.format = format; 3136 3137 image->stride = PNG_IMAGE_ROW_STRIDE(image->image) + image->stride_extra; 3138 allocbuffer(image); 3139 3140 result = png_image_finish_read(&image->image, background, 3141 image->buffer+16, (png_int_32)image->stride, image->colormap); 3142 3143 checkbuffer(image, image->file_name); 3144 3145 if (result) 3146 return checkopaque(image); 3147 3148 else 3149 return logerror(image, image->file_name, ": image read failed", ""); 3150 } 3151 } 3152 3153 /* Reads from a filename, which must be in image->file_name, but uses 3154 * image->opts to choose the method. The file is always read in its native 3155 * format (the one the simplified API suggests). 3156 */ 3157 static int 3158 read_one_file(Image *image) 3159 { 3160 if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO)) 3161 { 3162 /* memory or stdio. */ 3163 FILE *f = fopen(image->file_name, "rb"); 3164 3165 if (f != NULL) 3166 { 3167 if (image->opts & READ_FILE) 3168 image->input_file = f; 3169 3170 else /* memory */ 3171 { 3172 if (fseek(f, 0, SEEK_END) == 0) 3173 { 3174 long int cb = ftell(f); 3175 3176 if (cb > 0 && (unsigned long int)cb < (size_t)~(size_t)0) 3177 { 3178 png_bytep b = voidcast(png_bytep, malloc((size_t)cb)); 3179 3180 if (b != NULL) 3181 { 3182 rewind(f); 3183 3184 if (fread(b, (size_t)cb, 1, f) == 1) 3185 { 3186 fclose(f); 3187 image->input_memory_size = cb; 3188 image->input_memory = b; 3189 } 3190 3191 else 3192 { 3193 free(b); 3194 return logclose(image, f, image->file_name, 3195 ": read failed: "); 3196 } 3197 } 3198 3199 else 3200 return logclose(image, f, image->file_name, 3201 ": out of memory: "); 3202 } 3203 3204 else if (cb == 0) 3205 return logclose(image, f, image->file_name, 3206 ": zero length: "); 3207 3208 else 3209 return logclose(image, f, image->file_name, 3210 ": tell failed: "); 3211 } 3212 3213 else 3214 return logclose(image, f, image->file_name, ": seek failed: "); 3215 } 3216 } 3217 3218 else 3219 return logerror(image, image->file_name, ": open failed: ", 3220 strerror(errno)); 3221 } 3222 3223 return read_file(image, FORMAT_NO_CHANGE, NULL); 3224 } 3225 3226 #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED 3227 static int 3228 write_one_file(Image *output, Image *image, int convert_to_8bit) 3229 { 3230 if (image->opts & FAST_WRITE) 3231 image->image.flags |= PNG_IMAGE_FLAG_FAST; 3232 3233 if (image->opts & USE_STDIO) 3234 { 3235 FILE *f = tmpfile(); 3236 3237 if (f != NULL) 3238 { 3239 if (png_image_write_to_stdio(&image->image, f, convert_to_8bit, 3240 image->buffer+16, (png_int_32)image->stride, image->colormap)) 3241 { 3242 if (fflush(f) == 0) 3243 { 3244 rewind(f); 3245 initimage(output, image->opts, "tmpfile", image->stride_extra); 3246 output->input_file = f; 3247 if (!checkopaque(image)) 3248 return 0; 3249 } 3250 3251 else 3252 return logclose(image, f, "tmpfile", ": flush: "); 3253 } 3254 3255 else 3256 { 3257 fclose(f); 3258 return logerror(image, "tmpfile", ": write failed", ""); 3259 } 3260 } 3261 3262 else 3263 return logerror(image, "tmpfile", ": open: ", strerror(errno)); 3264 } 3265 3266 else 3267 { 3268 static int counter = 0; 3269 char name[32]; 3270 3271 sprintf(name, "%s%d.png", tmpf, ++counter); 3272 3273 if (png_image_write_to_file(&image->image, name, convert_to_8bit, 3274 image->buffer+16, (png_int_32)image->stride, image->colormap)) 3275 { 3276 initimage(output, image->opts, output->tmpfile_name, 3277 image->stride_extra); 3278 /* Afterwards, or freeimage will delete it! */ 3279 strcpy(output->tmpfile_name, name); 3280 3281 if (!checkopaque(image)) 3282 return 0; 3283 } 3284 3285 else 3286 return logerror(image, name, ": write failed", ""); 3287 } 3288 3289 /* 'output' has an initialized temporary image, read this back in and compare 3290 * this against the original: there should be no change since the original 3291 * format was written unmodified unless 'convert_to_8bit' was specified. 3292 * However, if the original image was color-mapped, a simple read will zap 3293 * the linear, color and maybe alpha flags, this will cause spurious failures 3294 * under some circumstances. 3295 */ 3296 if (read_file(output, image->image.format | FORMAT_NO_CHANGE, NULL)) 3297 { 3298 png_uint_32 original_format = image->image.format; 3299 3300 if (convert_to_8bit) 3301 original_format &= ~PNG_FORMAT_FLAG_LINEAR; 3302 3303 if ((output->image.format & BASE_FORMATS) != 3304 (original_format & BASE_FORMATS)) 3305 return logerror(image, image->file_name, ": format changed on read: ", 3306 output->file_name); 3307 3308 return compare_two_images(image, output, 0/*via linear*/, NULL); 3309 } 3310 3311 else 3312 return logerror(output, output->tmpfile_name, 3313 ": read of new file failed", ""); 3314 } 3315 #endif 3316 3317 static int 3318 testimage(Image *image, png_uint_32 opts, format_list *pf) 3319 { 3320 int result; 3321 Image copy; 3322 3323 /* Copy the original data, stealing it from 'image' */ 3324 checkopaque(image); 3325 copy = *image; 3326 3327 copy.opts = opts; 3328 copy.buffer = NULL; 3329 copy.bufsize = 0; 3330 copy.allocsize = 0; 3331 3332 image->input_file = NULL; 3333 image->input_memory = NULL; 3334 image->input_memory_size = 0; 3335 image->tmpfile_name[0] = 0; 3336 3337 { 3338 png_uint_32 counter; 3339 Image output; 3340 3341 newimage(&output); 3342 3343 result = 1; 3344 3345 /* Use the low bit of 'counter' to indicate whether or not to do alpha 3346 * removal with a background color or by composting onto the image; this 3347 * step gets skipped if it isn't relevant 3348 */ 3349 for (counter=0; counter<2*FORMAT_COUNT; ++counter) 3350 if (format_isset(pf, counter >> 1)) 3351 { 3352 png_uint_32 format = counter >> 1; 3353 3354 png_color background_color; 3355 png_colorp background = NULL; 3356 3357 /* If there is a format change that removes the alpha channel then 3358 * the background is relevant. If the output is 8-bit color-mapped 3359 * then a background color *must* be provided, otherwise there are 3360 * two tests to do - one with a color, the other with NULL. The 3361 * NULL test happens second. 3362 */ 3363 if ((counter & 1) == 0) 3364 { 3365 if ((format & PNG_FORMAT_FLAG_ALPHA) == 0 && 3366 (image->image.format & PNG_FORMAT_FLAG_ALPHA) != 0) 3367 { 3368 /* Alpha/transparency will be removed, the background is 3369 * relevant: make it a color the first time 3370 */ 3371 random_color(&background_color); 3372 background = &background_color; 3373 3374 /* BUT if the output is to a color-mapped 8-bit format then 3375 * the background must always be a color, so increment 'counter' 3376 * to skip the NULL test. 3377 */ 3378 if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0 && 3379 (format & PNG_FORMAT_FLAG_LINEAR) == 0) 3380 ++counter; 3381 } 3382 3383 /* Otherwise an alpha channel is not being eliminated, just leave 3384 * background NULL and skip the (counter & 1) NULL test. 3385 */ 3386 else 3387 ++counter; 3388 } 3389 /* else just use NULL for background */ 3390 3391 resetimage(©); 3392 copy.opts = opts; /* in case read_file needs to change it */ 3393 3394 result = read_file(©, format, background); 3395 if (!result) 3396 break; 3397 3398 /* Make sure the file just read matches the original file. */ 3399 result = compare_two_images(image, ©, 0/*via linear*/, background); 3400 if (!result) 3401 break; 3402 3403 # ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED 3404 /* Write the *copy* just made to a new file to make sure the write 3405 * side works ok. Check the conversion to sRGB if the copy is 3406 * linear. 3407 */ 3408 output.opts = opts; 3409 result = write_one_file(&output, ©, 0/*convert to 8bit*/); 3410 if (!result) 3411 break; 3412 3413 /* Validate against the original too; the background is needed here 3414 * as well so that compare_two_images knows what color was used. 3415 */ 3416 result = compare_two_images(image, &output, 0, background); 3417 if (!result) 3418 break; 3419 3420 if ((format & PNG_FORMAT_FLAG_LINEAR) != 0 && 3421 (format & PNG_FORMAT_FLAG_COLORMAP) == 0) 3422 { 3423 /* 'output' is linear, convert to the corresponding sRGB format. 3424 */ 3425 output.opts = opts; 3426 result = write_one_file(&output, ©, 1/*convert to 8bit*/); 3427 if (!result) 3428 break; 3429 3430 /* This may involve a conversion via linear; in the ideal world 3431 * this would round-trip correctly, but libpng 1.5.7 is not the 3432 * ideal world so allow a drift (error_via_linear). 3433 * 3434 * 'image' has an alpha channel but 'output' does not then there 3435 * will a strip-alpha-channel operation (because 'output' is 3436 * linear), handle this by composing on black when doing the 3437 * comparison. 3438 */ 3439 result = compare_two_images(image, &output, 1/*via_linear*/, 3440 background); 3441 if (!result) 3442 break; 3443 } 3444 # endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ 3445 } 3446 3447 freeimage(&output); 3448 } 3449 3450 freeimage(©); 3451 3452 return result; 3453 } 3454 3455 static int 3456 test_one_file(const char *file_name, format_list *formats, png_uint_32 opts, 3457 int stride_extra, int log_pass) 3458 { 3459 int result; 3460 Image image; 3461 3462 newimage(&image); 3463 initimage(&image, opts, file_name, stride_extra); 3464 result = read_one_file(&image); 3465 if (result) 3466 result = testimage(&image, opts, formats); 3467 freeimage(&image); 3468 3469 /* Ensure that stderr is flushed into any log file */ 3470 fflush(stderr); 3471 3472 if (log_pass) 3473 { 3474 if (result) 3475 printf("PASS:"); 3476 3477 else 3478 printf("FAIL:"); 3479 3480 # ifndef PNG_SIMPLIFIED_WRITE_SUPPORTED 3481 printf(" (no write)"); 3482 # endif 3483 3484 print_opts(opts); 3485 printf(" %s\n", file_name); 3486 /* stdout may not be line-buffered if it is piped to a file, so: */ 3487 fflush(stdout); 3488 } 3489 3490 else if (!result) 3491 exit(1); 3492 3493 return result; 3494 } 3495 3496 int 3497 main(int argc, char **argv) 3498 { 3499 png_uint_32 opts = FAST_WRITE; 3500 format_list formats; 3501 const char *touch = NULL; 3502 int log_pass = 0; 3503 int redundant = 0; 3504 int stride_extra = 0; 3505 int retval = 0; 3506 int c; 3507 3508 init_sRGB_to_d(); 3509 #if 0 3510 init_error_via_linear(); 3511 #endif 3512 format_init(&formats); 3513 3514 for (c=1; c<argc; ++c) 3515 { 3516 const char *arg = argv[c]; 3517 3518 if (strcmp(arg, "--log") == 0) 3519 log_pass = 1; 3520 else if (strcmp(arg, "--fresh") == 0) 3521 { 3522 memset(gpc_error, 0, sizeof gpc_error); 3523 memset(gpc_error_via_linear, 0, sizeof gpc_error_via_linear); 3524 } 3525 else if (strcmp(arg, "--file") == 0) 3526 # ifdef PNG_STDIO_SUPPORTED 3527 opts |= READ_FILE; 3528 # else 3529 return 77; /* skipped: no support */ 3530 # endif 3531 else if (strcmp(arg, "--memory") == 0) 3532 opts &= ~READ_FILE; 3533 else if (strcmp(arg, "--stdio") == 0) 3534 # ifdef PNG_STDIO_SUPPORTED 3535 opts |= USE_STDIO; 3536 # else 3537 return 77; /* skipped: no support */ 3538 # endif 3539 else if (strcmp(arg, "--name") == 0) 3540 opts &= ~USE_STDIO; 3541 else if (strcmp(arg, "--verbose") == 0) 3542 opts |= VERBOSE; 3543 else if (strcmp(arg, "--quiet") == 0) 3544 opts &= ~VERBOSE; 3545 else if (strcmp(arg, "--preserve") == 0) 3546 opts |= KEEP_TMPFILES; 3547 else if (strcmp(arg, "--nopreserve") == 0) 3548 opts &= ~KEEP_TMPFILES; 3549 else if (strcmp(arg, "--keep-going") == 0) 3550 opts |= KEEP_GOING; 3551 else if (strcmp(arg, "--fast") == 0) 3552 opts |= FAST_WRITE; 3553 else if (strcmp(arg, "--slow") == 0) 3554 opts &= ~FAST_WRITE; 3555 else if (strcmp(arg, "--accumulate") == 0) 3556 opts |= ACCUMULATE; 3557 else if (strcmp(arg, "--redundant") == 0) 3558 redundant = 1; 3559 else if (strcmp(arg, "--stop") == 0) 3560 opts &= ~KEEP_GOING; 3561 else if (strcmp(arg, "--strict") == 0) 3562 opts |= STRICT; 3563 else if (strcmp(arg, "--sRGB-16bit") == 0) 3564 opts |= sRGB_16BIT; 3565 else if (strcmp(arg, "--linear-16bit") == 0) 3566 opts &= ~sRGB_16BIT; 3567 else if (strcmp(arg, "--tmpfile") == 0) 3568 { 3569 if (c+1 < argc) 3570 { 3571 if (strlen(argv[++c]) >= sizeof tmpf) 3572 { 3573 fflush(stdout); 3574 fprintf(stderr, "%s: %s is too long for a temp file prefix\n", 3575 argv[0], argv[c]); 3576 exit(99); 3577 } 3578 3579 /* Safe: checked above */ 3580 strcpy(tmpf, argv[c]); 3581 } 3582 3583 else 3584 { 3585 fflush(stdout); 3586 fprintf(stderr, "%s: %s requires a temporary file prefix\n", 3587 argv[0], arg); 3588 exit(99); 3589 } 3590 } 3591 else if (strcmp(arg, "--touch") == 0) 3592 { 3593 if (c+1 < argc) 3594 touch = argv[++c]; 3595 3596 else 3597 { 3598 fflush(stdout); 3599 fprintf(stderr, "%s: %s requires a file name argument\n", 3600 argv[0], arg); 3601 exit(99); 3602 } 3603 } 3604 else if (arg[0] == '+') 3605 { 3606 png_uint_32 format = formatof(arg+1); 3607 3608 if (format > FORMAT_COUNT) 3609 exit(99); 3610 3611 format_set(&formats, format); 3612 } 3613 else if (arg[0] == '-' && arg[1] != 0 && (arg[1] != '0' || arg[2] != 0)) 3614 { 3615 fflush(stdout); 3616 fprintf(stderr, "%s: unknown option: %s\n", argv[0], arg); 3617 exit(99); 3618 } 3619 else 3620 { 3621 if (format_is_initial(&formats)) 3622 format_default(&formats, redundant); 3623 3624 if (arg[0] == '-') 3625 { 3626 const int term = (arg[1] == '0' ? 0 : '\n'); 3627 unsigned int ich = 0; 3628 3629 /* Loop reading files, use a static buffer to simplify this and just 3630 * stop if the name gets to long. 3631 */ 3632 static char buffer[4096]; 3633 3634 do 3635 { 3636 int ch = getchar(); 3637 3638 /* Don't allow '\0' in file names, and terminate with '\n' or, 3639 * for -0, just '\0' (use -print0 to find to make this work!) 3640 */ 3641 if (ch == EOF || ch == term || ch == 0) 3642 { 3643 buffer[ich] = 0; 3644 3645 if (ich > 0 && !test_one_file(buffer, &formats, opts, 3646 stride_extra, log_pass)) 3647 retval = 1; 3648 3649 if (ch == EOF) 3650 break; 3651 3652 ich = 0; 3653 --ich; /* so that the increment below sets it to 0 again */ 3654 } 3655 3656 else 3657 buffer[ich] = (char)ch; 3658 } while (++ich < sizeof buffer); 3659 3660 if (ich) 3661 { 3662 buffer[32] = 0; 3663 buffer[4095] = 0; 3664 fprintf(stderr, "%s...%s: file name too long\n", buffer, 3665 buffer+(4096-32)); 3666 exit(99); 3667 } 3668 } 3669 3670 else if (!test_one_file(arg, &formats, opts, stride_extra, log_pass)) 3671 retval = 1; 3672 } 3673 } 3674 3675 if (opts & ACCUMULATE) 3676 { 3677 unsigned int in; 3678 3679 printf("static png_uint_16 gpc_error[16/*in*/][16/*out*/][4/*a*/] =\n"); 3680 printf("{\n"); 3681 for (in=0; in<16; ++in) 3682 { 3683 unsigned int out; 3684 printf(" { /* input: %s */\n ", format_names[in]); 3685 for (out=0; out<16; ++out) 3686 { 3687 unsigned int alpha; 3688 printf(" {"); 3689 for (alpha=0; alpha<4; ++alpha) 3690 { 3691 printf(" %d", gpc_error[in][out][alpha]); 3692 if (alpha < 3) putchar(','); 3693 } 3694 printf(" }"); 3695 if (out < 15) 3696 { 3697 putchar(','); 3698 if (out % 4 == 3) printf("\n "); 3699 } 3700 } 3701 printf("\n }"); 3702 3703 if (in < 15) 3704 putchar(','); 3705 else 3706 putchar('\n'); 3707 } 3708 printf("};\n"); 3709 3710 printf("static png_uint_16 gpc_error_via_linear[16][4/*out*/][4] =\n"); 3711 printf("{\n"); 3712 for (in=0; in<16; ++in) 3713 { 3714 unsigned int out; 3715 printf(" { /* input: %s */\n ", format_names[in]); 3716 for (out=0; out<4; ++out) 3717 { 3718 unsigned int alpha; 3719 printf(" {"); 3720 for (alpha=0; alpha<4; ++alpha) 3721 { 3722 printf(" %d", gpc_error_via_linear[in][out][alpha]); 3723 if (alpha < 3) putchar(','); 3724 } 3725 printf(" }"); 3726 if (out < 3) 3727 putchar(','); 3728 } 3729 printf("\n }"); 3730 3731 if (in < 15) 3732 putchar(','); 3733 else 3734 putchar('\n'); 3735 } 3736 printf("};\n"); 3737 3738 printf("static png_uint_16 gpc_error_to_colormap[8/*i*/][8/*o*/][4] =\n"); 3739 printf("{\n"); 3740 for (in=0; in<8; ++in) 3741 { 3742 unsigned int out; 3743 printf(" { /* input: %s */\n ", format_names[in]); 3744 for (out=0; out<8; ++out) 3745 { 3746 unsigned int alpha; 3747 printf(" {"); 3748 for (alpha=0; alpha<4; ++alpha) 3749 { 3750 printf(" %d", gpc_error_to_colormap[in][out][alpha]); 3751 if (alpha < 3) putchar(','); 3752 } 3753 printf(" }"); 3754 if (out < 7) 3755 { 3756 putchar(','); 3757 if (out % 4 == 3) printf("\n "); 3758 } 3759 } 3760 printf("\n }"); 3761 3762 if (in < 7) 3763 putchar(','); 3764 else 3765 putchar('\n'); 3766 } 3767 printf("};\n"); 3768 } 3769 3770 if (retval == 0 && touch != NULL) 3771 { 3772 FILE *fsuccess = fopen(touch, "wt"); 3773 3774 if (fsuccess != NULL) 3775 { 3776 int error = 0; 3777 fprintf(fsuccess, "PNG simple API tests succeeded\n"); 3778 fflush(fsuccess); 3779 error = ferror(fsuccess); 3780 3781 if (fclose(fsuccess) || error) 3782 { 3783 fflush(stdout); 3784 fprintf(stderr, "%s: write failed\n", touch); 3785 exit(99); 3786 } 3787 } 3788 3789 else 3790 { 3791 fflush(stdout); 3792 fprintf(stderr, "%s: open failed\n", touch); 3793 exit(99); 3794 } 3795 } 3796 3797 return retval; 3798 } 3799 3800 #else /* !PNG_SIMPLIFIED_READ_SUPPORTED */ 3801 int main(void) 3802 { 3803 fprintf(stderr, "pngstest: no read support in libpng, test skipped\n"); 3804 /* So the test is skipped: */ 3805 return 77; 3806 } 3807 #endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ 3808