2 /* pngtest.c - a simple test program to test libpng
4 * libpng 1.0.9 - January 31, 2001
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1998-2001 Glenn Randers-Pehrson
7 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
10 * This program reads in a PNG image, writes it out again, and then
11 * compares the two files. If the files are identical, this shows that
12 * the basic chunk handling, filtering, and (de)compression code is working
13 * properly. It does not currently test all of the transforms, although
16 * The program will report "FAIL" in certain legitimate cases:
17 * 1) when the compression level or filter selection method is changed.
18 * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
19 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
20 * exist in the input file.
21 * 4) others not listed here...
22 * In these cases, it is best to check with another tool such as "pngcheck"
23 * to see what the differences between the two files are.
25 * If a filename is given on the command-line, then this file is used
26 * for the input, rather than the default "pngtest.png". This allows
27 * testing a wide variety of files easily. You can also test a number
28 * of files at once by typing "pngtest -m file1.png file2.png ..."
31 #if defined(_WIN32_WCE)
33 __error__ (f|w)printf functions are not supported on old WindowsCE.;
37 # define READFILE(file, data, length, check) \
38 if (ReadFile(file, data, length, &check,NULL)) check = 0
39 # define WRITEFILE(file, data, length, check)) \
40 if (WriteFile(file, data, length, &check, NULL)) check = 0
41 # define FCLOSE(file) CloseHandle(file)
46 # define READFILE(file, data, length, check) \
47 check=(png_size_t)fread(data,(png_size_t)1,length,file)
48 # define WRITEFILE(file, data, length, check) \
49 check=(png_size_t)fwrite(data,(png_size_t)1, length, file)
50 # define FCLOSE(file) fclose(file)
53 #if defined(PNG_NO_STDIO)
54 #if defined(_WIN32_WCE)
55 typedef HANDLE png_FILE_p;
57 typedef FILE * png_FILE_p;
61 /* Makes pngtest verbose so we can find problems (needs to be before png.h) */
67 #define PNGTEST_TIMING
70 #ifdef PNG_NO_FLOATING_POINT_SUPPORTED
75 static float t_start, t_stop, t_decode, t_encode, t_misc;
81 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
83 # define png_jmpbuf(png_ptr) png_ptr->jmpbuf
87 static float t_start, t_stop, t_decode, t_encode, t_misc;
88 #if !defined(PNG_tIME_SUPPORTED)
93 #if defined(PNG_TIME_RFC1123_SUPPORTED)
94 static int tIME_chunk_present=0;
95 static char tIME_string[30] = "no tIME chunk present in file";
98 static int verbose = 0;
100 int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
106 /* defined so I can write to a file on gui/windowing platforms */
107 /* #define STDERR stderr */
108 #define STDERR stdout /* for DOS */
110 /* example of using row callbacks to make a simple progress meter */
111 static int status_pass=1;
112 static int status_dots_requested=0;
113 static int status_dots=1;
116 read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
118 read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
120 if(png_ptr == NULL || row_number > PNG_MAX_UINT) return;
121 if(status_pass != pass)
123 fprintf(stdout,"\n Pass %d: ",pass);
130 fprintf(stdout, "\n ");
133 fprintf(stdout, "r");
137 write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
139 write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
141 if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return;
142 fprintf(stdout, "w");
146 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
147 /* Example of using user transform callback (we don't transform anything,
148 but merely examine the row filters. We set this to 256 rather than
149 5 in case illegal filter values are present.) */
150 static png_uint_32 filters_used[256];
152 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
154 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
156 if(png_ptr != NULL && row_info != NULL)
157 ++filters_used[*(data-1)];
161 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
162 /* example of using user transform callback (we don't transform anything,
163 but merely count the zero samples) */
165 static png_uint_32 zero_samples;
168 count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
170 count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
173 if(png_ptr == NULL)return;
175 /* contents of row_info:
176 * png_uint_32 width width of row
177 * png_uint_32 rowbytes number of bytes in row
178 * png_byte color_type color type of pixels
179 * png_byte bit_depth bit depth of samples
180 * png_byte channels number of channels (1-4)
181 * png_byte pixel_depth bits per pixel (depth*channels)
185 /* counts the number of zero samples (or zero pixels if color_type is 3 */
187 if(row_info->color_type == 0 || row_info->color_type == 3)
190 png_uint_32 n, nstop;
191 for (n=0, nstop=row_info->width; n<nstop; n++)
193 if(row_info->bit_depth == 1)
195 if(((*dp << pos++ ) & 0x80) == 0) zero_samples++;
202 if(row_info->bit_depth == 2)
204 if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++;
211 if(row_info->bit_depth == 4)
213 if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++;
220 if(row_info->bit_depth == 8)
221 if(*dp++ == 0) zero_samples++;
222 if(row_info->bit_depth == 16)
224 if((*dp | *(dp+1)) == 0) zero_samples++;
229 else /* other color types */
231 png_uint_32 n, nstop;
233 int color_channels = row_info->channels;
234 if(row_info->color_type > 3)color_channels--;
236 for (n=0, nstop=row_info->width; n<nstop; n++)
238 for (channel = 0; channel < color_channels; channel++)
240 if(row_info->bit_depth == 8)
241 if(*dp++ == 0) zero_samples++;
242 if(row_info->bit_depth == 16)
244 if((*dp | *(dp+1)) == 0) zero_samples++;
248 if(row_info->color_type > 3)
251 if(row_info->bit_depth == 16)dp++;
256 #endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
258 static int wrote_question = 0;
260 #if defined(PNG_NO_STDIO)
261 /* START of code to validate stdio-free compilation */
262 /* These copies of the default read/write functions come from pngrio.c and */
263 /* pngwio.c. They allow "don't include stdio" testing of the library. */
264 /* This is the function that does the actual reading of data. If you are
265 not reading from a standard C stream, you should create a replacement
266 read_data function and use it at run time with png_set_read_fn(), rather
267 than changing the library. */
269 #ifndef USE_FAR_KEYWORD
271 pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
275 /* fread() returns 0 on error, so it is OK to store this in a png_size_t
276 * instead of an int, which is what fread() actually returns.
278 READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
282 png_error(png_ptr, "Read Error");
286 /* this is the model-independent version. Since the standard I/O library
287 can't handle far buffers in the medium and small models, we have to copy
291 #define NEAR_BUF_SIZE 1024
292 #define MIN(a,b) (a <= b ? a : b)
295 pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
301 /* Check if data really is near. If so, use usual code. */
302 n_data = (png_byte *)CVT_PTR_NOCHECK(data);
303 io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
304 if ((png_bytep)n_data == data)
306 READFILE(io_ptr, n_data, length, check);
310 png_byte buf[NEAR_BUF_SIZE];
311 png_size_t read, remaining, err;
316 read = MIN(NEAR_BUF_SIZE, remaining);
317 READFILE(io_ptr, buf, 1, err);
318 png_memcpy(data, buf, read); /* copy far buffer to near buffer */
326 while (remaining != 0);
330 png_error(png_ptr, "read Error");
333 #endif /* USE_FAR_KEYWORD */
335 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
337 pngtest_flush(png_structp png_ptr)
339 #if !defined(_WIN32_WCE)
341 io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
348 /* This is the function that does the actual writing of data. If you are
349 not writing to a standard C stream, you should create a replacement
350 write_data function and use it at run time with png_set_write_fn(), rather
351 than changing the library. */
352 #ifndef USE_FAR_KEYWORD
354 pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
358 WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
361 png_error(png_ptr, "Write Error");
365 /* this is the model-independent version. Since the standard I/O library
366 can't handle far buffers in the medium and small models, we have to copy
370 #define NEAR_BUF_SIZE 1024
371 #define MIN(a,b) (a <= b ? a : b)
374 pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
377 png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
380 /* Check if data really is near. If so, use usual code. */
381 near_data = (png_byte *)CVT_PTR_NOCHECK(data);
382 io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
383 if ((png_bytep)near_data == data)
385 WRITEFILE(io_ptr, near_data, length, check);
389 png_byte buf[NEAR_BUF_SIZE];
390 png_size_t written, remaining, err;
395 written = MIN(NEAR_BUF_SIZE, remaining);
396 png_memcpy(buf, data, written); /* copy far buffer to near buffer */
397 WRITEFILE(io_ptr, buf, written, err);
403 remaining -= written;
405 while (remaining != 0);
409 png_error(png_ptr, "Write Error");
413 #endif /* USE_FAR_KEYWORD */
415 /* This function is called when there is a warning, but the library thinks
416 * it can continue anyway. Replacement functions don't have to do anything
417 * here if you don't want to. In the default configuration, png_ptr is
418 * not used, but it is passed in case it may be useful.
421 pngtest_warning(png_structp png_ptr, png_const_charp message)
423 PNG_CONST char *name = "UNKNOWN (ERROR!)";
424 if (png_ptr != NULL && png_ptr->error_ptr != NULL)
425 name = png_ptr->error_ptr;
426 fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
429 /* This is the default error handling function. Note that replacements for
430 * this function MUST NOT RETURN, or the program will likely crash. This
431 * function is used by default, or if the program supplies NULL for the
432 * error function pointer in png_set_error_fn().
435 pngtest_error(png_structp png_ptr, png_const_charp message)
437 pngtest_warning(png_ptr, message);
438 /* We can return because png_error calls the default handler, which is
439 * actually OK in this case. */
441 #endif /* PNG_NO_STDIO */
442 /* END of code to validate stdio-free compilation */
444 /* START of code to validate memory allocation and deallocation */
445 #ifdef PNG_USER_MEM_SUPPORTED
447 /* Allocate memory. For reasonable files, size should never exceed
448 64K. However, zlib may allocate more then 64K if you don't tell
449 it not to. See zconf.h and png.h for more information. zlib does
450 need to allocate exactly 64K, so whatever you call here must
451 have the ability to do that.
453 This piece of code can be compiled to validate max 64K allocations
454 by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
455 typedef struct memory_information
459 struct memory_information FAR *next;
460 } memory_information;
461 typedef memory_information FAR *memory_infop;
463 static memory_infop pinformation = NULL;
464 static int current_allocation = 0;
465 static int maximum_allocation = 0;
466 static int total_allocation = 0;
467 static int num_allocations = 0;
469 extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr,
471 extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr,
475 png_debug_malloc(png_structp png_ptr, png_uint_32 size)
478 /* png_malloc has already tested for NULL; png_create_struct calls
479 png_debug_malloc directly, with png_ptr == NULL which is OK */
482 return (png_voidp)(NULL);
484 /* This calls the library allocator twice, once to get the requested
485 buffer and once to get a new free list entry. */
487 memory_infop pinfo = png_malloc_default(png_ptr, sizeof *pinfo);
489 current_allocation += size;
490 total_allocation += size;
492 if (current_allocation > maximum_allocation)
493 maximum_allocation = current_allocation;
494 pinfo->pointer = png_malloc_default(png_ptr, size);
495 pinfo->next = pinformation;
496 pinformation = pinfo;
497 /* Make sure the caller isn't assuming zeroed memory. */
498 png_memset(pinfo->pointer, 0xdd, pinfo->size);
501 printf("png_malloc %d bytes at %x\n",size,pinfo->pointer);
503 assert(pinfo->size != 12345678);
504 return (png_voidp)(pinfo->pointer);
508 /* Free a pointer. It is removed from the list at the same time. */
510 png_debug_free(png_structp png_ptr, png_voidp ptr)
513 fprintf(STDERR, "NULL pointer to png_debug_free.\n");
516 #if 0 /* This happens all the time. */
517 fprintf(STDERR, "WARNING: freeing NULL pointer\n");
522 /* Unlink the element from the list. */
524 memory_infop FAR *ppinfo = &pinformation;
527 memory_infop pinfo = *ppinfo;
528 if (pinfo->pointer == ptr)
530 *ppinfo = pinfo->next;
531 current_allocation -= pinfo->size;
532 if (current_allocation < 0)
533 fprintf(STDERR, "Duplicate free of memory\n");
534 /* We must free the list element too, but first kill
535 the memory that is to be freed. */
536 memset(ptr, 0x55, pinfo->size);
537 png_free_default(png_ptr, pinfo);
541 if (pinfo->next == NULL)
543 fprintf(STDERR, "Pointer %x not found\n", ptr);
546 ppinfo = &pinfo->next;
550 /* Finally free the data. */
553 printf("Freeing %x\n",ptr);
555 png_free_default(png_ptr, ptr);
558 #endif /* PNG_USER_MEM_SUPPORTED */
559 /* END of code to test memory allocation/deallocation */
563 test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
565 static png_FILE_p fpin;
566 static png_FILE_p fpout; /* "static" prevents setjmp corruption */
567 png_structp read_ptr, write_ptr;
568 png_infop read_info_ptr, write_info_ptr, end_info_ptr, write_end_info_ptr;
571 png_uint_32 width, height;
573 int bit_depth, color_type;
574 #ifdef PNG_SETJMP_SUPPORTED
575 #ifdef USE_FAR_KEYWORD
580 #if defined(_WIN32_WCE)
581 TCHAR path[MAX_PATH];
583 char inbuf[256], outbuf[256];
585 row_buf = (png_bytep)NULL;
587 #if defined(_WIN32_WCE)
588 MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
589 if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
591 if ((fpin = fopen(inname, "rb")) == NULL)
594 fprintf(STDERR, "Could not find input file %s\n", inname);
598 #if defined(_WIN32_WCE)
599 MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
600 if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
602 if ((fpout = fopen(outname, "wb")) == NULL)
605 fprintf(STDERR, "Could not open output file %s\n", outname);
610 png_debug(0, "Allocating read and write structures\n");
611 #ifdef PNG_USER_MEM_SUPPORTED
612 read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
613 (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
614 (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
616 read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
617 (png_error_ptr)NULL, (png_error_ptr)NULL);
619 #if defined(PNG_NO_STDIO)
620 png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
623 #ifdef PNG_USER_MEM_SUPPORTED
624 write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
625 (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
626 (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
628 write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
629 (png_error_ptr)NULL, (png_error_ptr)NULL);
631 #if defined(PNG_NO_STDIO)
632 png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
635 png_debug(0, "Allocating read_info, write_info and end_info structures\n");
636 read_info_ptr = png_create_info_struct(read_ptr);
637 write_info_ptr = png_create_info_struct(write_ptr);
638 end_info_ptr = png_create_info_struct(read_ptr);
639 write_end_info_ptr = png_create_info_struct(write_ptr);
640 #ifdef PNG_USER_MEM_SUPPORTED
643 #ifdef PNG_SETJMP_SUPPORTED
644 png_debug(0, "Setting jmpbuf for read struct\n");
645 #ifdef USE_FAR_KEYWORD
648 if (setjmp(png_jmpbuf(read_ptr)))
651 fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
652 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
653 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
654 png_destroy_write_struct(&write_ptr, &write_info_ptr);
659 #ifdef USE_FAR_KEYWORD
660 png_memcpy(png_jmpbuf(read_ptr),jmpbuf,sizeof(jmp_buf));
663 png_debug(0, "Setting jmpbuf for write struct\n");
664 #ifdef USE_FAR_KEYWORD
667 if (setjmp(png_jmpbuf(write_ptr)))
670 fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
671 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
672 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
673 png_destroy_write_struct(&write_ptr, &write_info_ptr);
678 #ifdef USE_FAR_KEYWORD
679 png_memcpy(png_jmpbuf(write_ptr),jmpbuf,sizeof(jmp_buf));
683 png_debug(0, "Initializing input and output streams\n");
684 #if !defined(PNG_NO_STDIO)
685 png_init_io(read_ptr, fpin);
686 png_init_io(write_ptr, fpout);
688 png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
689 png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data,
690 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
696 if(status_dots_requested == 1)
698 png_set_write_status_fn(write_ptr, write_row_callback);
699 png_set_read_status_fn(read_ptr, read_row_callback);
703 png_set_write_status_fn(write_ptr, NULL);
704 png_set_read_status_fn(read_ptr, NULL);
707 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
712 png_set_read_user_transform_fn(read_ptr, count_filters);
715 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
717 png_set_write_user_transform_fn(write_ptr, count_zero_samples);
720 #define HANDLE_CHUNK_IF_SAFE 2
721 #define HANDLE_CHUNK_ALWAYS 3
722 #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
723 png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, NULL, 0);
725 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
726 png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, NULL, 0);
729 png_debug(0, "Reading info struct\n");
730 png_read_info(read_ptr, read_info_ptr);
732 png_debug(0, "Transferring info struct\n");
734 int interlace_type, compression_type, filter_type;
736 if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
737 &color_type, &interlace_type, &compression_type, &filter_type))
739 png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
740 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
741 color_type, interlace_type, compression_type, filter_type);
743 color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
747 #if defined(PNG_FIXED_POINT_SUPPORTED)
748 #if defined(PNG_cHRM_SUPPORTED)
750 png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
752 if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
753 &red_y, &green_x, &green_y, &blue_x, &blue_y))
755 png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
756 red_y, green_x, green_y, blue_x, blue_y);
760 #if defined(PNG_gAMA_SUPPORTED)
762 png_fixed_point gamma;
764 if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
766 png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
770 #else /* Use floating point versions */
771 #if defined(PNG_FLOATING_POINT_SUPPORTED)
772 #if defined(PNG_cHRM_SUPPORTED)
774 double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
776 if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
777 &red_y, &green_x, &green_y, &blue_x, &blue_y))
779 png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
780 red_y, green_x, green_y, blue_x, blue_y);
784 #if defined(PNG_gAMA_SUPPORTED)
788 if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
790 png_set_gAMA(write_ptr, write_info_ptr, gamma);
794 #endif /* floating point */
795 #endif /* fixed point */
796 #if defined(PNG_iCCP_SUPPORTED)
801 int compression_type;
803 if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
806 png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
811 #if defined(PNG_sRGB_SUPPORTED)
815 if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
817 png_set_sRGB(write_ptr, write_info_ptr, intent);
825 if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
827 png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
830 #if defined(PNG_bKGD_SUPPORTED)
832 png_color_16p background;
834 if (png_get_bKGD(read_ptr, read_info_ptr, &background))
836 png_set_bKGD(write_ptr, write_info_ptr, background);
840 #if defined(PNG_hIST_SUPPORTED)
844 if (png_get_hIST(read_ptr, read_info_ptr, &hist))
846 png_set_hIST(write_ptr, write_info_ptr, hist);
850 #if defined(PNG_oFFs_SUPPORTED)
852 png_int_32 offset_x, offset_y;
855 if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
857 png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
861 #if defined(PNG_pCAL_SUPPORTED)
863 png_charp purpose, units;
868 if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
869 &nparams, &units, ¶ms))
871 png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
872 nparams, units, params);
876 #if defined(PNG_pHYs_SUPPORTED)
878 png_uint_32 res_x, res_y;
881 if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
883 png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
887 #if defined(PNG_sBIT_SUPPORTED)
889 png_color_8p sig_bit;
891 if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
893 png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
897 #if defined(PNG_sCAL_SUPPORTED)
898 #ifdef PNG_FLOATING_POINT_SUPPORTED
901 double scal_width, scal_height;
903 if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
906 png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
910 #ifdef PNG_FIXED_POINT_SUPPORTED
913 png_charp scal_width, scal_height;
915 if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
918 png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height);
924 #if defined(PNG_TEXT_SUPPORTED)
929 if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
931 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
932 png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
936 #if defined(PNG_tIME_SUPPORTED)
940 if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
942 png_set_tIME(write_ptr, write_info_ptr, mod_time);
943 #if defined(PNG_TIME_RFC1123_SUPPORTED)
944 /* we have to use png_strcpy instead of "=" because the string
945 pointed to by png_convert_to_rfc1123() gets free'ed before
947 png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
948 tIME_chunk_present++;
949 #endif /* PNG_TIME_RFC1123_SUPPORTED */
953 #if defined(PNG_tRNS_SUPPORTED)
957 png_color_16p trans_values;
959 if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
962 png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
967 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
969 png_unknown_chunkp unknowns;
970 int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
975 png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
977 /* copy the locations from the read_info_ptr. The automatically
978 generated locations in write_info_ptr are wrong because we
979 haven't written anything yet */
980 for (i = 0; i < (png_size_t)num_unknowns; i++)
981 png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
982 unknowns[i].location);
987 png_debug(0, "\nWriting info struct\n");
989 /* If we wanted, we could write info in two steps:
990 png_write_info_before_PLTE(write_ptr, write_info_ptr);
992 png_write_info(write_ptr, write_info_ptr);
994 png_debug(0, "\nAllocating row buffer \n");
995 row_buf = (png_bytep)png_malloc(read_ptr,
996 png_get_rowbytes(read_ptr, read_info_ptr));
999 fprintf(STDERR, "No memory to allocate row buffer\n");
1000 png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL);
1001 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1002 png_destroy_write_struct(&write_ptr, &write_info_ptr);
1007 png_debug(0, "Writing row data\n");
1009 #if defined(PNG_READ_INTERLACING_SUPPORTED) || \
1010 defined(PNG_WRITE_INTERLACING_SUPPORTED)
1011 num_pass = png_set_interlace_handling(read_ptr);
1012 png_set_interlace_handling(write_ptr);
1017 #ifdef PNGTEST_TIMING
1018 t_stop = (float)clock();
1019 t_misc += (t_stop - t_start);
1022 for (pass = 0; pass < num_pass; pass++)
1024 png_debug1(0, "Writing row data for pass %d\n",pass);
1025 for (y = 0; y < height; y++)
1027 png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
1028 #ifdef PNGTEST_TIMING
1029 t_stop = (float)clock();
1030 t_decode += (t_stop - t_start);
1033 png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1034 #ifdef PNGTEST_TIMING
1035 t_stop = (float)clock();
1036 t_encode += (t_stop - t_start);
1042 #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
1043 png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1045 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1046 png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1049 png_debug(0, "Reading and writing end_info data\n");
1051 png_read_end(read_ptr, end_info_ptr);
1052 #if defined(PNG_TEXT_SUPPORTED)
1057 if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
1059 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
1060 png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
1064 #if defined(PNG_tIME_SUPPORTED)
1068 if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
1070 png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1071 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1072 /* we have to use png_strcpy instead of "=" because the string
1073 pointed to by png_convert_to_rfc1123() gets free'ed before
1075 png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
1076 tIME_chunk_present++;
1077 #endif /* PNG_TIME_RFC1123_SUPPORTED */
1081 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1083 png_unknown_chunkp unknowns;
1085 num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
1090 png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1092 /* copy the locations from the read_info_ptr. The automatically
1093 generated locations in write_end_info_ptr are wrong because we
1094 haven't written the end_info yet */
1095 for (i = 0; i < (png_size_t)num_unknowns; i++)
1096 png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1097 unknowns[i].location);
1101 png_write_end(write_ptr, write_end_info_ptr);
1103 #ifdef PNG_EASY_ACCESS_SUPPORTED
1106 png_uint_32 iwidth, iheight;
1107 iwidth = png_get_image_width(write_ptr, write_info_ptr);
1108 iheight = png_get_image_height(write_ptr, write_info_ptr);
1109 fprintf(STDERR, "Image width = %lu, height = %lu\n",
1114 png_debug(0, "Destroying data structs\n");
1115 png_free(read_ptr, row_buf);
1117 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1118 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1119 png_destroy_write_struct(&write_ptr, &write_info_ptr);
1124 png_debug(0, "Opening files for comparison\n");
1125 #if defined(_WIN32_WCE)
1126 MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
1127 if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1129 if ((fpin = fopen(inname, "rb")) == NULL)
1132 fprintf(STDERR, "Could not find file %s\n", inname);
1136 #if defined(_WIN32_WCE)
1137 MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
1138 if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1140 if ((fpout = fopen(outname, "rb")) == NULL)
1143 fprintf(STDERR, "Could not find file %s\n", outname);
1150 png_size_t num_in, num_out;
1152 READFILE(fpin, inbuf, 1, num_in);
1153 READFILE(fpout, outbuf, 1, num_out);
1155 if (num_in != num_out)
1157 fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1159 if(wrote_question == 0)
1162 " Was %s written with the same maximum IDAT chunk size (%d bytes),",
1163 inname,PNG_ZBUF_SIZE);
1165 "\n filtering heuristic (libpng default), compression");
1167 " level (zlib default),\n and zlib version (%s)?\n\n",
1179 if (png_memcmp(inbuf, outbuf, num_in))
1181 fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1182 if(wrote_question == 0)
1185 " Was %s written with the same maximum IDAT chunk size (%d bytes),",
1186 inname,PNG_ZBUF_SIZE);
1188 "\n filtering heuristic (libpng default), compression");
1190 " level (zlib default),\n and zlib version (%s)?\n\n",
1206 /* input and output filenames */
1208 static PNG_CONST char *inname = "pngtest/png";
1209 static PNG_CONST char *outname = "pngout/png";
1211 static PNG_CONST char *inname = "pngtest.png";
1212 static PNG_CONST char *outname = "pngout.png";
1216 main(int argc, char *argv[])
1221 fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1222 fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION);
1223 fprintf(STDERR,"%s",png_get_copyright(NULL));
1224 /* Show the version of libpng used in building the library */
1225 fprintf(STDERR," library (%lu):%s", png_access_version_number(),
1226 png_get_header_version(NULL));
1227 /* Show the version of libpng used in building the application */
1228 fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1229 PNG_HEADER_VERSION_STRING);
1230 fprintf(STDERR," sizeof(png_struct)=%d, sizeof(png_info)=%d\n",
1231 sizeof(png_struct), sizeof(png_info));
1233 /* Do some consistency checking on the memory allocation settings, I'm
1234 not sure this matters, but it is nice to know, the first of these
1235 tests should be impossible because of the way the macros are set
1237 #if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1238 fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1240 /* I think the following can happen. */
1241 #if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1242 fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1245 if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
1248 "Warning: versions are different between png.h and png.c\n");
1249 fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING);
1250 fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver);
1256 if (strcmp(argv[1], "-m") == 0)
1259 status_dots_requested = 0;
1261 else if (strcmp(argv[1], "-mv") == 0 ||
1262 strcmp(argv[1], "-vm") == 0 )
1266 status_dots_requested = 1;
1268 else if (strcmp(argv[1], "-v") == 0)
1271 status_dots_requested = 1;
1277 status_dots_requested = 0;
1281 if (!multiple && argc == 3+verbose)
1282 outname = argv[2+verbose];
1284 if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
1287 "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1290 " reads/writes one PNG file (without -m) or multiple files (-m)\n");
1292 " with -m %s is used as a temporary file\n", outname);
1299 #ifdef PNG_USER_MEM_SUPPORTED
1300 int allocation_now = current_allocation;
1302 for (i=2; i<argc; ++i)
1304 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1308 fprintf(STDERR, "Testing %s:",argv[i]);
1309 kerror = test_one_file(argv[i], outname);
1312 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1313 fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1315 fprintf(STDERR, " PASS\n");
1317 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1318 for (k=0; k<256; k++)
1320 fprintf(STDERR, " Filter %d was used %lu times\n",
1323 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1324 if(tIME_chunk_present != 0)
1325 fprintf(STDERR, " tIME = %s\n",tIME_string);
1326 tIME_chunk_present = 0;
1327 #endif /* PNG_TIME_RFC1123_SUPPORTED */
1331 fprintf(STDERR, " FAIL\n");
1334 #ifdef PNG_USER_MEM_SUPPORTED
1335 if (allocation_now != current_allocation)
1336 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1337 current_allocation-allocation_now);
1338 if (current_allocation != 0)
1340 memory_infop pinfo = pinformation;
1342 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1343 current_allocation);
1344 while (pinfo != NULL)
1346 fprintf(STDERR, " %d bytes at %x\n", pinfo->size, pinfo->pointer);
1347 pinfo = pinfo->next;
1352 #ifdef PNG_USER_MEM_SUPPORTED
1353 fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1354 current_allocation);
1355 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1356 maximum_allocation);
1357 fprintf(STDERR, " Total memory allocation: %10d bytes\n",
1359 fprintf(STDERR, " Number of allocations: %10d\n",
1369 #ifdef PNG_USER_MEM_SUPPORTED
1370 int allocation_now = current_allocation;
1372 if (i == 1) status_dots_requested = 1;
1373 else if(verbose == 0)status_dots_requested = 0;
1374 if (i == 0 || verbose == 1 || ierror != 0)
1375 fprintf(STDERR, "Testing %s:",inname);
1376 kerror = test_one_file(inname, outname);
1379 if(verbose == 1 || i == 2)
1381 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1384 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1385 fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1387 fprintf(STDERR, " PASS\n");
1389 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1390 for (k=0; k<256; k++)
1392 fprintf(STDERR, " Filter %d was used %lu times\n",
1395 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1396 if(tIME_chunk_present != 0)
1397 fprintf(STDERR, " tIME = %s\n",tIME_string);
1398 #endif /* PNG_TIME_RFC1123_SUPPORTED */
1403 if(verbose == 0 && i != 2)
1404 fprintf(STDERR, "Testing %s:",inname);
1405 fprintf(STDERR, " FAIL\n");
1408 #ifdef PNG_USER_MEM_SUPPORTED
1409 if (allocation_now != current_allocation)
1410 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1411 current_allocation-allocation_now);
1412 if (current_allocation != 0)
1414 memory_infop pinfo = pinformation;
1416 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1417 current_allocation);
1418 while (pinfo != NULL)
1420 fprintf(STDERR," %d bytes at %x\n",
1421 pinfo->size, pinfo->pointer);
1422 pinfo = pinfo->next;
1427 #ifdef PNG_USER_MEM_SUPPORTED
1428 fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1429 current_allocation);
1430 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1431 maximum_allocation);
1432 fprintf(STDERR, " Total memory allocation: %10d bytes\n",
1434 fprintf(STDERR, " Number of allocations: %10d\n",
1439 #ifdef PNGTEST_TIMING
1440 t_stop = (float)clock();
1441 t_misc += (t_stop - t_start);
1443 fprintf(STDERR," CPU time used = %.3f seconds",
1444 (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1445 fprintf(STDERR," (decoding %.3f,\n",
1446 t_decode/(float)CLOCKS_PER_SEC);
1447 fprintf(STDERR," encoding %.3f ,",
1448 t_encode/(float)CLOCKS_PER_SEC);
1449 fprintf(STDERR," other %.3f seconds)\n\n",
1450 t_misc/(float)CLOCKS_PER_SEC);
1454 fprintf(STDERR, "libpng passes test\n");
1456 fprintf(STDERR, "libpng FAILS test\n");
1457 return (int)(ierror != 0);
1460 /* Generate a compiler error if there is an old png.h in the search path. */
1461 typedef version_1_0_9 your_png_h_is_not_version_1_0_9;