]> git.saurik.com Git - wxWidgets.git/blame - src/png/pngtest.c
~wxBufferedStream puts back unread bytes
[wxWidgets.git] / src / png / pngtest.c
CommitLineData
c801d85f
KB
1
2/* pngtest.c - a simple test program to test libpng
3 *
a626cc03 4 * libpng 1.0.3 -January 14, 1999
c801d85f
KB
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
7 * Copyright (c) 1996, 1997 Andreas Dilger
a626cc03 8 * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
c801d85f
KB
9 *
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
14 * it probably should.
15 *
a626cc03 16 * The program will report "FAIL" in certain legitimate cases:
c801d85f 17 * 1) when the compression level or filter selection method is changed.
a626cc03 18 * 2) when the chunk size is not 8K.
c801d85f
KB
19 * 3) unknown ancillary chunks exist in the input file.
20 * 4) others not listed here...
21 * In these cases, it is best to check with another tool such as "pngcheck"
22 * to see what the differences between the two images are.
23 *
24 * If a filename is given on the command-line, then this file is used
25 * for the input, rather than the default "pngtest.png". This allows
a626cc03
RR
26 * testing a wide variety of files easily. You can also test a number
27 * of files at once by typing "pngtest -m file1.png file2.png ..."
c801d85f
KB
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32
33/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
34#ifndef PNG_DEBUG
35#define PNG_DEBUG 0
36#endif
37
a626cc03
RR
38#include "png.h"
39
40#if defined(PNG_TIME_RFC1123_SUPPORTED)
41static int tIME_chunk_present=0;
42static char tIME_string[30] = "no tIME chunk present in file";
43#endif /* PNG_TIME_RFC1123_SUPPORTED */
c801d85f
KB
44
45int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
46
47#ifdef __TURBOC__
48#include <mem.h>
49#endif
50
51/* defined so I can write to a file on gui/windowing platforms */
52/* #define STDERR stderr */
53#define STDERR stdout /* for DOS */
54
55/* example of using row callbacks to make a simple progress meter */
56static int status_pass=1;
57static int status_dots_requested=0;
58static int status_dots=1;
59
60void
61read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
62{
63 if(png_ptr == NULL || row_number > 0x3fffffffL) return;
64 if(status_pass != pass)
65 {
66 fprintf(stdout,"\n Pass %d: ",pass);
67 status_pass = pass;
68 status_dots = 30;
69 }
70 status_dots--;
71 if(status_dots == 0)
72 {
73 fprintf(stdout, "\n ");
74 status_dots=30;
75 }
76 fprintf(stdout, "r");
77}
78
79void
80write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
81{
82 if(png_ptr == NULL || row_number > 0x3fffffffL || pass > 7) return;
83 fprintf(stdout, "w");
84}
85
86
87#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
88/* example of using user transform callback (we don't transform anything,
a626cc03 89 but merely count the zero samples) */
c801d85f 90
a626cc03 91static png_uint_32 zero_samples;
c801d85f
KB
92
93void
a626cc03 94count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
c801d85f
KB
95{
96 png_bytep dp = data;
a626cc03 97 if(png_ptr == NULL)return;
c801d85f
KB
98
99 /* contents of row_info:
100 * png_uint_32 width width of row
101 * png_uint_32 rowbytes number of bytes in row
102 * png_byte color_type color type of pixels
103 * png_byte bit_depth bit depth of samples
104 * png_byte channels number of channels (1-4)
105 * png_byte pixel_depth bits per pixel (depth*channels)
106 */
107
a626cc03 108 /* counts the number of zero samples (or zero pixels if color_type is 3 */
c801d85f
KB
109
110 if(row_info->color_type == 0 || row_info->color_type == 3)
111 {
112 int pos=0;
a626cc03
RR
113 png_uint_32 n, nstop;
114 for (n=0, nstop=row_info->width; n<nstop; n++)
c801d85f
KB
115 {
116 if(row_info->bit_depth == 1)
a626cc03
RR
117 {
118 if(((*dp << pos++ )& 0x80) == 0) zero_samples++;
c801d85f
KB
119 if(pos == 8)
120 {
a626cc03 121 pos = 0;
c801d85f
KB
122 dp++;
123 }
a626cc03 124 }
c801d85f 125 if(row_info->bit_depth == 2)
a626cc03
RR
126 {
127 if(((*dp << (pos+=2))& 0xc0) == 0) zero_samples++;
c801d85f
KB
128 if(pos == 8)
129 {
a626cc03 130 pos = 0;
c801d85f
KB
131 dp++;
132 }
a626cc03 133 }
c801d85f 134 if(row_info->bit_depth == 4)
a626cc03
RR
135 {
136 if(((*dp << (pos+=4))& 0xf0) == 0) zero_samples++;
c801d85f
KB
137 if(pos == 8)
138 {
a626cc03 139 pos = 0;
c801d85f
KB
140 dp++;
141 }
a626cc03 142 }
c801d85f 143 if(row_info->bit_depth == 8)
a626cc03 144 if(*dp++ == 0) zero_samples++;
c801d85f
KB
145 if(row_info->bit_depth == 16)
146 {
a626cc03 147 if((*dp | *(dp+1)) == 0) zero_samples++;
c801d85f
KB
148 dp+=2;
149 }
150 }
151 }
152 else /* other color types */
153 {
a626cc03 154 png_uint_32 n, nstop;
c801d85f
KB
155 int channel;
156 int color_channels = row_info->channels;
157 if(row_info->color_type > 3)color_channels--;
158
a626cc03 159 for (n=0, nstop=row_info->width; n<nstop; n++)
c801d85f
KB
160 {
161 for (channel = 0; channel < color_channels; channel++)
162 {
163 if(row_info->bit_depth == 8)
a626cc03 164 if(*dp++ == 0) zero_samples++;
c801d85f
KB
165 if(row_info->bit_depth == 16)
166 {
a626cc03 167 if((*dp | *(dp+1)) == 0) zero_samples++;
c801d85f
KB
168 dp+=2;
169 }
170 }
171 if(row_info->color_type > 3)
172 {
173 dp++;
174 if(row_info->bit_depth == 16)dp++;
175 }
176 }
177 }
178}
179#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
180
181static int verbose = 0;
182static int wrote_question = 0;
183
184#if defined(PNG_NO_STDIO)
185/* START of code to validate stdio-free compilation */
186/* These copies of the default read/write functions come from pngrio.c and */
187/* pngwio.c. They allow "don't include stdio" testing of the library. */
a626cc03 188/* This is the function that does the actual reading of data. If you are
c801d85f
KB
189 not reading from a standard C stream, you should create a replacement
190 read_data function and use it at run time with png_set_read_fn(), rather
191 than changing the library. */
192#ifndef USE_FAR_KEYWORD
193static void
194png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
195{
196 png_size_t check;
197
198 /* fread() returns 0 on error, so it is OK to store this in a png_size_t
199 * instead of an int, which is what fread() actually returns.
200 */
201 check = (png_size_t)fread(data, (png_size_t)1, length,
202 (FILE *)png_ptr->io_ptr);
203
204 if (check != length)
205 {
206 png_error(png_ptr, "Read Error");
207 }
208}
209#else
210/* this is the model-independent version. Since the standard I/O library
211 can't handle far buffers in the medium and small models, we have to copy
212 the data.
213*/
a626cc03 214
c801d85f
KB
215#define NEAR_BUF_SIZE 1024
216#define MIN(a,b) (a <= b ? a : b)
a626cc03 217
c801d85f
KB
218static void
219png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
220{
221 int check;
222 png_byte *n_data;
223 FILE *io_ptr;
224
225 /* Check if data really is near. If so, use usual code. */
226 n_data = (png_byte *)CVT_PTR_NOCHECK(data);
227 io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
228 if ((png_bytep)n_data == data)
229 {
230 check = fread(n_data, 1, length, io_ptr);
231 }
232 else
233 {
234 png_byte buf[NEAR_BUF_SIZE];
235 png_size_t read, remaining, err;
236 check = 0;
237 remaining = length;
238 do
239 {
240 read = MIN(NEAR_BUF_SIZE, remaining);
241 err = fread(buf, (png_size_t)1, read, io_ptr);
242 png_memcpy(data, buf, read); /* copy far buffer to near buffer */
243 if(err != read)
244 break;
245 else
246 check += err;
247 data += read;
248 remaining -= read;
249 }
250 while (remaining != 0);
251 }
252 if (check != length)
253 {
254 png_error(png_ptr, "read Error");
255 }
256}
257#endif /* USE_FAR_KEYWORD */
258
259#if defined(PNG_WRITE_FLUSH_SUPPORTED)
260static void
261png_default_flush(png_structp png_ptr)
262{
263 FILE *io_ptr;
264 io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
265 if (io_ptr != NULL)
266 fflush(io_ptr);
267}
268#endif
269
a626cc03 270/* This is the function that does the actual writing of data. If you are
c801d85f
KB
271 not writing to a standard C stream, you should create a replacement
272 write_data function and use it at run time with png_set_write_fn(), rather
273 than changing the library. */
274#ifndef USE_FAR_KEYWORD
275static void
276png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
277{
278 png_uint_32 check;
279
280 check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
281 if (check != length)
282 {
283 png_error(png_ptr, "Write Error");
284 }
285}
286#else
287/* this is the model-independent version. Since the standard I/O library
288 can't handle far buffers in the medium and small models, we have to copy
289 the data.
290*/
291
292#define NEAR_BUF_SIZE 1024
293#define MIN(a,b) (a <= b ? a : b)
294
295static void
296png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
297{
298 png_uint_32 check;
299 png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
300 FILE *io_ptr;
301
302 /* Check if data really is near. If so, use usual code. */
303 near_data = (png_byte *)CVT_PTR_NOCHECK(data);
304 io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
305 if ((png_bytep)near_data == data)
306 {
307 check = fwrite(near_data, 1, length, io_ptr);
308 }
309 else
310 {
311 png_byte buf[NEAR_BUF_SIZE];
312 png_size_t written, remaining, err;
313 check = 0;
314 remaining = length;
315 do
316 {
317 written = MIN(NEAR_BUF_SIZE, remaining);
318 png_memcpy(buf, data, written); /* copy far buffer to near buffer */
319 err = fwrite(buf, 1, written, io_ptr);
320 if (err != written)
321 break;
322 else
323 check += err;
324 data += written;
325 remaining -= written;
326 }
327 while (remaining != 0);
328 }
329 if (check != length)
330 {
331 png_error(png_ptr, "Write Error");
332 }
333}
334
335#endif /* USE_FAR_KEYWORD */
336
337/* This function is called when there is a warning, but the library thinks
338 * it can continue anyway. Replacement functions don't have to do anything
339 * here if you don't want to. In the default configuration, png_ptr is
340 * not used, but it is passed in case it may be useful.
341 */
342static void
343png_default_warning(png_structp png_ptr, png_const_charp message)
344{
345 PNG_CONST char *name = "UNKNOWN (ERROR!)";
346 if (png_ptr != NULL && png_ptr->error_ptr != NULL)
347 name = png_ptr->error_ptr;
348 fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
349}
350
351/* This is the default error handling function. Note that replacements for
352 * this function MUST NOT RETURN, or the program will likely crash. This
353 * function is used by default, or if the program supplies NULL for the
354 * error function pointer in png_set_error_fn().
355 */
356static void
357png_default_error(png_structp png_ptr, png_const_charp message)
358{
359 png_default_warning(png_ptr, message);
a626cc03
RR
360 /* We can return because png_error calls the default handler, which is
361 * actually OK in this case. */
c801d85f
KB
362}
363#endif /* PNG_NO_STDIO */
364/* END of code to validate stdio-free compilation */
365
366/* START of code to validate memory allocation and deallocation */
a626cc03 367#ifdef PNG_USER_MEM_SUPPORTED
c801d85f
KB
368
369/* Allocate memory. For reasonable files, size should never exceed
370 64K. However, zlib may allocate more then 64K if you don't tell
371 it not to. See zconf.h and png.h for more information. zlib does
372 need to allocate exactly 64K, so whatever you call here must
373 have the ability to do that.
374
375 This piece of code can be compiled to validate max 64K allocations
376 by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
377typedef struct memory_information {
378 png_uint_32 size;
a626cc03 379 png_voidp pointer;
c801d85f
KB
380 struct memory_information FAR *next;
381} memory_information;
382typedef memory_information FAR *memory_infop;
383
384static memory_infop pinformation = NULL;
385static int current_allocation = 0;
386static int maximum_allocation = 0;
387
388extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr,
389 png_uint_32 size));
390extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr,
391 png_voidp ptr));
392
393png_voidp
a626cc03
RR
394png_debug_malloc(png_structp png_ptr, png_uint_32 size) {
395
396 /* png_malloc has already tested for NULL; png_create_struct calls
397 png_debug_malloc directly, with png_ptr == NULL which is OK */
398
c801d85f
KB
399 if (size == 0)
400 return (png_voidp)(NULL);
401
402 /* This calls the library allocator twice, once to get the requested
403 buffer and once to get a new free list entry. */
404 {
a626cc03 405 memory_infop pinfo = png_malloc_default(png_ptr, sizeof *pinfo);
c801d85f
KB
406 pinfo->size = size;
407 current_allocation += size;
408 if (current_allocation > maximum_allocation)
409 maximum_allocation = current_allocation;
a626cc03 410 pinfo->pointer = png_malloc_default(png_ptr, size);
c801d85f
KB
411 pinfo->next = pinformation;
412 pinformation = pinfo;
413 /* Make sure the caller isn't assuming zeroed memory. */
414 png_memset(pinfo->pointer, 0xdd, pinfo->size);
415 return (png_voidp)(pinfo->pointer);
416 }
417}
418
419/* Free a pointer. It is removed from the list at the same time. */
420void
a626cc03 421png_debug_free(png_structp png_ptr, png_voidp ptr)
c801d85f
KB
422{
423 if (png_ptr == NULL)
a626cc03 424 fprintf(STDERR, "NULL pointer to png_debug_free.\n");
c801d85f
KB
425 if (ptr == 0) {
426#if 0 /* This happens all the time. */
427 fprintf(STDERR, "WARNING: freeing NULL pointer\n");
428#endif
429 return;
430 }
431
432 /* Unlink the element from the list. */
433 {
434 memory_infop FAR *ppinfo = &pinformation;
435 for (;;) {
436 memory_infop pinfo = *ppinfo;
437 if (pinfo->pointer == ptr) {
438 *ppinfo = pinfo->next;
439 current_allocation -= pinfo->size;
440 if (current_allocation < 0)
441 fprintf(STDERR, "Duplicate free of memory\n");
442 /* We must free the list element too, but first kill
a626cc03 443 the memory that is to be freed. */
c801d85f 444 memset(ptr, 0x55, pinfo->size);
a626cc03 445 png_free_default(png_ptr, pinfo);
c801d85f
KB
446 break;
447 }
448 if (pinfo->next == NULL) {
449 fprintf(STDERR, "Pointer %x not found\n", ptr);
450 break;
451 }
452 ppinfo = &pinfo->next;
453 }
454 }
455
456 /* Finally free the data. */
a626cc03 457 png_free_default(png_ptr, ptr);
c801d85f 458}
a626cc03 459#endif /* PNG_USER_MEM_SUPPORTED */
c801d85f
KB
460/* END of code to test memory allocation/deallocation */
461
462/* Test one file */
463int
464test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
465{
466 static FILE *fpin, *fpout; /* "static" prevents setjmp corruption */
467 png_structp read_ptr, write_ptr;
468 png_infop read_info_ptr, write_info_ptr, end_info_ptr;
469 png_bytep row_buf;
470 png_uint_32 y;
471 png_uint_32 width, height;
472 int num_pass, pass;
473 int bit_depth, color_type;
474#ifdef USE_FAR_KEYWORD
475 jmp_buf jmpbuf;
476#endif
a626cc03 477
c801d85f
KB
478 char inbuf[256], outbuf[256];
479
480 row_buf = (png_bytep)NULL;
481
482 if ((fpin = fopen(inname, "rb")) == NULL)
483 {
484 fprintf(STDERR, "Could not find input file %s\n", inname);
485 return (1);
486 }
487
488 if ((fpout = fopen(outname, "wb")) == NULL)
489 {
490 fprintf(STDERR, "Could not open output file %s\n", outname);
491 fclose(fpin);
492 return (1);
493 }
494
495 png_debug(0, "Allocating read and write structures\n");
a626cc03
RR
496#ifdef PNG_USER_MEM_SUPPORTED
497 read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
498 (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
499 (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
500#else
c801d85f
KB
501 read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
502 (png_error_ptr)NULL, (png_error_ptr)NULL);
a626cc03 503#endif
c801d85f
KB
504#if defined(PNG_NO_STDIO)
505 png_set_error_fn(read_ptr, (png_voidp)inname, png_default_error,
506 png_default_warning);
507#endif
a626cc03
RR
508#ifdef PNG_USER_MEM_SUPPORTED
509 write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
510 (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
511 (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
512#else
c801d85f
KB
513 write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
514 (png_error_ptr)NULL, (png_error_ptr)NULL);
a626cc03 515#endif
c801d85f
KB
516#if defined(PNG_NO_STDIO)
517 png_set_error_fn(write_ptr, (png_voidp)inname, png_default_error,
518 png_default_warning);
519#endif
520 png_debug(0, "Allocating read_info, write_info and end_info structures\n");
521 read_info_ptr = png_create_info_struct(read_ptr);
522 write_info_ptr = png_create_info_struct(write_ptr);
523 end_info_ptr = png_create_info_struct(read_ptr);
a626cc03
RR
524#ifdef PNG_USER_MEM_SUPPORTED
525#endif
c801d85f
KB
526
527 png_debug(0, "Setting jmpbuf for read struct\n");
528#ifdef USE_FAR_KEYWORD
529 if (setjmp(jmpbuf))
530#else
531 if (setjmp(read_ptr->jmpbuf))
532#endif
533 {
534 fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
535 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
536 png_destroy_write_struct(&write_ptr, &write_info_ptr);
537 fclose(fpin);
538 fclose(fpout);
539 return (1);
540 }
a626cc03
RR
541#ifdef USE_FAR_KEYWORD
542 png_memcpy(read_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
543#endif
c801d85f
KB
544
545 png_debug(0, "Setting jmpbuf for write struct\n");
546#ifdef USE_FAR_KEYWORD
c801d85f
KB
547 if (setjmp(jmpbuf))
548#else
549 if (setjmp(write_ptr->jmpbuf))
550#endif
551 {
552 fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
553 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
554 png_destroy_write_struct(&write_ptr, &write_info_ptr);
555 fclose(fpin);
556 fclose(fpout);
557 return (1);
558 }
c801d85f
KB
559#ifdef USE_FAR_KEYWORD
560 png_memcpy(write_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
561#endif
a626cc03 562
c801d85f
KB
563 png_debug(0, "Initializing input and output streams\n");
564#if !defined(PNG_NO_STDIO)
565 png_init_io(read_ptr, fpin);
566 png_init_io(write_ptr, fpout);
567#else
568 png_set_read_fn(read_ptr, (png_voidp)fpin, png_default_read_data);
569 png_set_write_fn(write_ptr, (png_voidp)fpout, png_default_write_data,
570#if defined(PNG_WRITE_FLUSH_SUPPORTED)
571 png_default_flush);
572#else
573 NULL);
574#endif
575#endif
576 if(status_dots_requested == 1)
577 {
578 png_set_write_status_fn(write_ptr, write_row_callback);
579 png_set_read_status_fn(read_ptr, read_row_callback);
580 }
581 else
582 {
583 png_set_write_status_fn(write_ptr, NULL);
584 png_set_read_status_fn(read_ptr, NULL);
585 }
586
587# if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
a626cc03
RR
588 zero_samples=0;
589 png_set_write_user_transform_fn(write_ptr, count_zero_samples);
c801d85f
KB
590# endif
591
592 png_debug(0, "Reading info struct\n");
593 png_read_info(read_ptr, read_info_ptr);
594
595 png_debug(0, "Transferring info struct\n");
596 {
597 int interlace_type, compression_type, filter_type;
598
599 if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
600 &color_type, &interlace_type, &compression_type, &filter_type))
601 {
602 png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
603#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
604 color_type, interlace_type, compression_type, filter_type);
605#else
606 color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
607#endif
608 }
609 }
610#if defined(PNG_READ_bKGD_SUPPORTED) && defined(PNG_WRITE_bKGD_SUPPORTED)
611 {
612 png_color_16p background;
613
614 if (png_get_bKGD(read_ptr, read_info_ptr, &background))
615 {
616 png_set_bKGD(write_ptr, write_info_ptr, background);
617 }
618 }
619#endif
620#if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED)
621 {
622 double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
623
624 if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
625 &red_y, &green_x, &green_y, &blue_x, &blue_y))
626 {
627 png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
628 red_y, green_x, green_y, blue_x, blue_y);
629 }
630 }
631#endif
632#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED)
633 {
634 double gamma;
635
636 if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
637 {
638 png_set_gAMA(write_ptr, write_info_ptr, gamma);
639 }
640 }
641#endif
642#if defined(PNG_READ_sRGB_SUPPORTED) && defined(PNG_WRITE_sRGB_SUPPORTED)
643 {
644 int intent;
645
646 if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
647 {
648 png_set_sRGB(write_ptr, write_info_ptr, intent);
649 }
650 }
651#endif
652#if defined(PNG_READ_hIST_SUPPORTED) && defined(PNG_WRITE_hIST_SUPPORTED)
653 {
654 png_uint_16p hist;
655
656 if (png_get_hIST(read_ptr, read_info_ptr, &hist))
657 {
658 png_set_hIST(write_ptr, write_info_ptr, hist);
659 }
660 }
661#endif
662#if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED)
663 {
664 png_uint_32 offset_x, offset_y;
665 int unit_type;
666
667 if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
668 {
669 png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
670 }
671 }
672#endif
673#if defined(PNG_READ_pCAL_SUPPORTED) && defined(PNG_WRITE_pCAL_SUPPORTED)
674 {
675 png_charp purpose, units;
676 png_charpp params;
677 png_int_32 X0, X1;
678 int type, nparams;
679
680 if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
681 &nparams, &units, &params))
682 {
683 png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
684 nparams, units, params);
685 }
686 }
687#endif
688#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED)
689 {
690 png_uint_32 res_x, res_y;
691 int unit_type;
692
693 if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
694 {
695 png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
696 }
697 }
698#endif
699 {
700 png_colorp palette;
701 int num_palette;
702
703 if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
704 {
705 png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
706 }
707 }
708#if defined(PNG_READ_sBIT_SUPPORTED) && defined(PNG_WRITE_sBIT_SUPPORTED)
709 {
710 png_color_8p sig_bit;
711
712 if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
713 {
714 png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
715 }
716 }
717#endif
718#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) || \
719 (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED))
720 {
721 png_textp text_ptr;
722 int num_text;
723
724 if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
725 {
726 png_debug1(0, "Handling %d tEXt/zTXt chunks\n", num_text);
727 png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
728 }
729 }
730#endif
731#if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED)
732 {
733 png_timep mod_time;
734
735 if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
736 {
737 png_set_tIME(write_ptr, write_info_ptr, mod_time);
a626cc03
RR
738#if defined(PNG_TIME_RFC1123_SUPPORTED)
739 /* we have to use png_strcpy instead of "=" because the string
740 pointed to by png_convert_to_rfc1123() gets free'ed before
741 we use it */
742 png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
743 tIME_chunk_present++;
744#endif /* PNG_TIME_RFC1123_SUPPORTED */
c801d85f
KB
745 }
746 }
747#endif
748#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED)
749 {
750 png_bytep trans;
751 int num_trans;
752 png_color_16p trans_values;
753
754 if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
755 &trans_values))
756 {
757 png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
758 trans_values);
759 }
760 }
761#endif
762
763 png_debug(0, "\nWriting info struct\n");
764 png_write_info(write_ptr, write_info_ptr);
765
766 png_debug(0, "\nAllocating row buffer \n");
a626cc03 767 row_buf = (png_bytep)png_malloc(read_ptr,
c801d85f
KB
768 png_get_rowbytes(read_ptr, read_info_ptr));
769 if (row_buf == NULL)
770 {
771 fprintf(STDERR, "No memory to allocate row buffer\n");
772 png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL);
773 png_destroy_write_struct(&write_ptr, &write_info_ptr);
774 fclose(fpin);
775 fclose(fpout);
776 return (1);
777 }
778 png_debug(0, "Writing row data\n");
779
780 num_pass = png_set_interlace_handling(read_ptr);
781 png_set_interlace_handling(write_ptr);
782
783 for (pass = 0; pass < num_pass; pass++)
784 {
785 png_debug1(0, "Writing row data for pass %d\n",pass);
786 for (y = 0; y < height; y++)
787 {
788 png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
789 png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
790 }
791 }
792
793 png_debug(0, "Reading and writing end_info data\n");
794 png_read_end(read_ptr, end_info_ptr);
795 png_write_end(write_ptr, end_info_ptr);
a626cc03 796
c801d85f
KB
797#ifdef PNG_EASY_ACCESS_SUPPORTED
798 if(verbose)
799 {
800 png_uint_32 iwidth, iheight;
801 iwidth = png_get_image_width(write_ptr, write_info_ptr);
802 iheight = png_get_image_height(write_ptr, write_info_ptr);
803 fprintf(STDERR, "Image width = %lu, height = %lu\n",
804 iwidth, iheight);
805 }
806#endif
807
808 png_debug(0, "Destroying data structs\n");
809 png_free(read_ptr, row_buf);
810 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
811 png_destroy_write_struct(&write_ptr, &write_info_ptr);
812
813 fclose(fpin);
814 fclose(fpout);
815
816 png_debug(0, "Opening files for comparison\n");
817 if ((fpin = fopen(inname, "rb")) == NULL)
818 {
819 fprintf(STDERR, "Could not find file %s\n", inname);
820 return (1);
821 }
822
823 if ((fpout = fopen(outname, "rb")) == NULL)
824 {
825 fprintf(STDERR, "Could not find file %s\n", outname);
826 fclose(fpin);
827 return (1);
828 }
829
830 for(;;)
831 {
832 png_size_t num_in, num_out;
833
834 num_in = fread(inbuf, 1, 1, fpin);
835 num_out = fread(outbuf, 1, 1, fpout);
836
837 if (num_in != num_out)
838 {
839 fprintf(STDERR, "Files %s and %s are of a different size\n",
840 inname, outname);
841 if(wrote_question == 0)
842 {
843 fprintf(STDERR,
844 " Was %s written with the same chunk size (8k),",inname);
845 fprintf(STDERR,
846 " filtering\n heuristic (libpng default), compression");
847 fprintf(STDERR,
848 " level (zlib default)\n and zlib version (%s)?\n\n",
849 ZLIB_VERSION);
850 wrote_question=1;
851 }
852 fclose(fpin);
853 fclose(fpout);
854 return (0);
855 }
856
857 if (!num_in)
858 break;
859
860 if (png_memcmp(inbuf, outbuf, num_in))
861 {
862 fprintf(STDERR, "Files %s and %s are different\n", inname, outname);
863 if(wrote_question == 0)
864 {
865 fprintf(STDERR,
866 " Was %s written with the same chunk size (8k),",inname);
867 fprintf(STDERR,
868 " filtering\n heuristic (libpng default), compression");
869 fprintf(STDERR,
870 " level (zlib default)\n and zlib version (%s)?\n\n",
871 ZLIB_VERSION);
872 wrote_question=1;
873 }
874 fclose(fpin);
875 fclose(fpout);
876 return (0);
877 }
878 }
879
880 fclose(fpin);
881 fclose(fpout);
882
883 return (0);
884}
885
886/* input and output filenames */
887#ifdef RISCOS
888PNG_CONST char *inname = "pngtest/png";
889PNG_CONST char *outname = "pngout/png";
890#else
891static PNG_CONST char *inname = "pngtest.png";
892static PNG_CONST char *outname = "pngout.png";
893#endif
894
895int
896main(int argc, char *argv[])
897{
898 int multiple = 0;
899 int ierror = 0;
900
901 fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
902 fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION);
a626cc03 903 fprintf(STDERR,"%s",png_get_copyright(NULL));
c801d85f
KB
904
905 /* Do some consistency checking on the memory allocation settings, I'm
906 not sure this matters, but it is nice to know, the first of these
907 tests should be impossible because of the way the macros are set
908 in pngconf.h */
909#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
910 fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
911#endif
912 /* I think the following can happen. */
913#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
914 fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
915#endif
916
917 if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
918 {
919 fprintf(STDERR,
920 "Warning: versions are different between png.h and png.c\n");
921 fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING);
922 fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver);
923 ++ierror;
924 }
925
926 if (argc > 1)
927 {
928 if (strcmp(argv[1], "-m") == 0)
929 {
930 multiple = 1;
931 status_dots_requested = 0;
932 }
933 else if (strcmp(argv[1], "-mv") == 0 ||
934 strcmp(argv[1], "-vm") == 0 )
935 {
936 multiple = 1;
937 verbose = 1;
938 status_dots_requested = 1;
939 }
940 else if (strcmp(argv[1], "-v") == 0)
941 {
942 verbose = 1;
943 status_dots_requested = 1;
944 inname = argv[2];
945 }
946 else
947 {
948 inname = argv[1];
949 status_dots_requested = 0;
950 }
951 }
952
953 if (!multiple && argc == 3+verbose)
954 outname = argv[2+verbose];
955
956 if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
957 {
958 fprintf(STDERR,
959 "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
960 argv[0], argv[0]);
961 fprintf(STDERR,
962 " reads/writes one PNG file (without -m) or multiple files (-m)\n");
963 fprintf(STDERR,
964 " with -m %s is used as a temporary file\n", outname);
965 exit(1);
966 }
967
968 if (multiple)
969 {
970 int i;
a626cc03 971#ifdef PNG_USER_MEM_SUPPORTED
c801d85f
KB
972 int allocation_now = current_allocation;
973#endif
974 for (i=2; i<argc; ++i)
975 {
976 int kerror;
977 fprintf(STDERR, "Testing %s:",argv[i]);
978 kerror = test_one_file(argv[i], outname);
a626cc03
RR
979 if (kerror == 0)
980 {
c801d85f 981#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
a626cc03 982 fprintf(STDERR, " PASS (%lu zero samples)\n",zero_samples);
c801d85f
KB
983#else
984 fprintf(STDERR, " PASS\n");
985#endif
a626cc03
RR
986#if defined(PNG_TIME_RFC1123_SUPPORTED)
987 if(tIME_chunk_present != 0)
988 fprintf(STDERR, " tIME = %s\n",tIME_string);
989 tIME_chunk_present = 0;
990#endif /* PNG_TIME_RFC1123_SUPPORTED */
991 }
992 else
993 {
c801d85f
KB
994 fprintf(STDERR, " FAIL\n");
995 ierror += kerror;
a626cc03
RR
996 }
997#ifdef PNG_USER_MEM_SUPPORTED
c801d85f
KB
998 if (allocation_now != current_allocation)
999 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1000 current_allocation-allocation_now);
1001 if (current_allocation != 0) {
1002 memory_infop pinfo = pinformation;
1003
1004 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1005 current_allocation);
1006 while (pinfo != NULL) {
1007 fprintf(STDERR, " %d bytes at %x\n", pinfo->size, pinfo->pointer);
1008 pinfo = pinfo->next;
1009 }
1010 }
1011#endif
1012 }
a626cc03 1013#ifdef PNG_USER_MEM_SUPPORTED
c801d85f
KB
1014 fprintf(STDERR, "Maximum memory allocation: %d bytes\n",
1015 maximum_allocation);
1016#endif
1017 }
1018 else
1019 {
1020 int i;
1021 for (i=0; i<3; ++i) {
1022 int kerror;
a626cc03 1023#ifdef PNG_USER_MEM_SUPPORTED
c801d85f
KB
1024 int allocation_now = current_allocation;
1025#endif
1026 if (i == 1) status_dots_requested = 1;
1027 else if(verbose == 0)status_dots_requested = 0;
1028 if (i == 0 || verbose == 1 || ierror != 0)
1029 fprintf(STDERR, "Testing %s:",inname);
1030 kerror = test_one_file(inname, outname);
1031 if(kerror == 0)
1032 {
1033 if(verbose == 1 || i == 2)
a626cc03 1034 {
c801d85f 1035#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
a626cc03 1036 fprintf(STDERR, " PASS (%lu zero samples)\n",zero_samples);
c801d85f
KB
1037#else
1038 fprintf(STDERR, " PASS\n");
1039#endif
a626cc03
RR
1040#if defined(PNG_TIME_RFC1123_SUPPORTED)
1041 if(tIME_chunk_present != 0)
1042 fprintf(STDERR, " tIME = %s\n",tIME_string);
1043#endif /* PNG_TIME_RFC1123_SUPPORTED */
1044 }
c801d85f
KB
1045 }
1046 else
1047 {
1048 if(verbose == 0 && i != 2)
1049 fprintf(STDERR, "Testing %s:",inname);
1050 fprintf(STDERR, " FAIL\n");
1051 ierror += kerror;
1052 }
a626cc03 1053#ifdef PNG_USER_MEM_SUPPORTED
c801d85f
KB
1054 if (allocation_now != current_allocation)
1055 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1056 current_allocation-allocation_now);
1057 if (current_allocation != 0) {
1058 memory_infop pinfo = pinformation;
a626cc03 1059
c801d85f
KB
1060 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1061 current_allocation);
1062 while (pinfo != NULL) {
1063 fprintf(STDERR, " %d bytes at %x\n", pinfo->size, pinfo->pointer);
1064 pinfo = pinfo->next;
1065 }
1066 }
1067#endif
1068 }
a626cc03 1069#ifdef PNG_USER_MEM_SUPPORTED
c801d85f
KB
1070 fprintf(STDERR, "Maximum memory allocation: %d bytes\n",
1071 maximum_allocation);
1072#endif
1073 }
1074
1075 if (ierror == 0)
1076 fprintf(STDERR, "libpng passes test\n");
1077 else
1078 fprintf(STDERR, "libpng FAILS test\n");
1079 return (int)(ierror != 0);
1080}
a626cc03 1081