]> git.saurik.com Git - wxWidgets.git/blob - src/png/pngtest.c
Committing in .
[wxWidgets.git] / src / png / pngtest.c
1
2 /* pngtest.c - a simple test program to test libpng
3 *
4 * libpng 1.0.3 -January 14, 1999
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
8 * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
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 *
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 chunk size is not 8K.
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
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 ..."
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
38 #include "png.h"
39
40 #if defined(PNG_TIME_RFC1123_SUPPORTED)
41 static int tIME_chunk_present=0;
42 static char tIME_string[30] = "no tIME chunk present in file";
43 #endif /* PNG_TIME_RFC1123_SUPPORTED */
44
45 int 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 */
56 static int status_pass=1;
57 static int status_dots_requested=0;
58 static int status_dots=1;
59
60 void
61 read_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
79 void
80 write_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,
89 but merely count the zero samples) */
90
91 static png_uint_32 zero_samples;
92
93 void
94 count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
95 {
96 png_bytep dp = data;
97 if(png_ptr == NULL)return;
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
108 /* counts the number of zero samples (or zero pixels if color_type is 3 */
109
110 if(row_info->color_type == 0 || row_info->color_type == 3)
111 {
112 int pos=0;
113 png_uint_32 n, nstop;
114 for (n=0, nstop=row_info->width; n<nstop; n++)
115 {
116 if(row_info->bit_depth == 1)
117 {
118 if(((*dp << pos++ )& 0x80) == 0) zero_samples++;
119 if(pos == 8)
120 {
121 pos = 0;
122 dp++;
123 }
124 }
125 if(row_info->bit_depth == 2)
126 {
127 if(((*dp << (pos+=2))& 0xc0) == 0) zero_samples++;
128 if(pos == 8)
129 {
130 pos = 0;
131 dp++;
132 }
133 }
134 if(row_info->bit_depth == 4)
135 {
136 if(((*dp << (pos+=4))& 0xf0) == 0) zero_samples++;
137 if(pos == 8)
138 {
139 pos = 0;
140 dp++;
141 }
142 }
143 if(row_info->bit_depth == 8)
144 if(*dp++ == 0) zero_samples++;
145 if(row_info->bit_depth == 16)
146 {
147 if((*dp | *(dp+1)) == 0) zero_samples++;
148 dp+=2;
149 }
150 }
151 }
152 else /* other color types */
153 {
154 png_uint_32 n, nstop;
155 int channel;
156 int color_channels = row_info->channels;
157 if(row_info->color_type > 3)color_channels--;
158
159 for (n=0, nstop=row_info->width; n<nstop; n++)
160 {
161 for (channel = 0; channel < color_channels; channel++)
162 {
163 if(row_info->bit_depth == 8)
164 if(*dp++ == 0) zero_samples++;
165 if(row_info->bit_depth == 16)
166 {
167 if((*dp | *(dp+1)) == 0) zero_samples++;
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
181 static int verbose = 0;
182 static 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. */
188 /* This is the function that does the actual reading of data. If you are
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
193 static void
194 png_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 */
214
215 #define NEAR_BUF_SIZE 1024
216 #define MIN(a,b) (a <= b ? a : b)
217
218 static void
219 png_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)
260 static void
261 png_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
270 /* This is the function that does the actual writing of data. If you are
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
275 static void
276 png_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
295 static void
296 png_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 */
342 static void
343 png_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 */
356 static void
357 png_default_error(png_structp png_ptr, png_const_charp message)
358 {
359 png_default_warning(png_ptr, message);
360 /* We can return because png_error calls the default handler, which is
361 * actually OK in this case. */
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 */
367 #ifdef PNG_USER_MEM_SUPPORTED
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. */
377 typedef struct memory_information {
378 png_uint_32 size;
379 png_voidp pointer;
380 struct memory_information FAR *next;
381 } memory_information;
382 typedef memory_information FAR *memory_infop;
383
384 static memory_infop pinformation = NULL;
385 static int current_allocation = 0;
386 static int maximum_allocation = 0;
387
388 extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr,
389 png_uint_32 size));
390 extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr,
391 png_voidp ptr));
392
393 png_voidp
394 png_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
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 {
405 memory_infop pinfo = png_malloc_default(png_ptr, sizeof *pinfo);
406 pinfo->size = size;
407 current_allocation += size;
408 if (current_allocation > maximum_allocation)
409 maximum_allocation = current_allocation;
410 pinfo->pointer = png_malloc_default(png_ptr, size);
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. */
420 void
421 png_debug_free(png_structp png_ptr, png_voidp ptr)
422 {
423 if (png_ptr == NULL)
424 fprintf(STDERR, "NULL pointer to png_debug_free.\n");
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
443 the memory that is to be freed. */
444 memset(ptr, 0x55, pinfo->size);
445 png_free_default(png_ptr, pinfo);
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. */
457 png_free_default(png_ptr, ptr);
458 }
459 #endif /* PNG_USER_MEM_SUPPORTED */
460 /* END of code to test memory allocation/deallocation */
461
462 /* Test one file */
463 int
464 test_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
477
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");
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
501 read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
502 (png_error_ptr)NULL, (png_error_ptr)NULL);
503 #endif
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
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
513 write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
514 (png_error_ptr)NULL, (png_error_ptr)NULL);
515 #endif
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);
524 #ifdef PNG_USER_MEM_SUPPORTED
525 #endif
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 }
541 #ifdef USE_FAR_KEYWORD
542 png_memcpy(read_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
543 #endif
544
545 png_debug(0, "Setting jmpbuf for write struct\n");
546 #ifdef USE_FAR_KEYWORD
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 }
559 #ifdef USE_FAR_KEYWORD
560 png_memcpy(write_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
561 #endif
562
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)
588 zero_samples=0;
589 png_set_write_user_transform_fn(write_ptr, count_zero_samples);
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);
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 */
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");
767 row_buf = (png_bytep)png_malloc(read_ptr,
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);
796
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
888 PNG_CONST char *inname = "pngtest/png";
889 PNG_CONST char *outname = "pngout/png";
890 #else
891 static PNG_CONST char *inname = "pngtest.png";
892 static PNG_CONST char *outname = "pngout.png";
893 #endif
894
895 int
896 main(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);
903 fprintf(STDERR,"%s",png_get_copyright(NULL));
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;
971 #ifdef PNG_USER_MEM_SUPPORTED
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);
979 if (kerror == 0)
980 {
981 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
982 fprintf(STDERR, " PASS (%lu zero samples)\n",zero_samples);
983 #else
984 fprintf(STDERR, " PASS\n");
985 #endif
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 {
994 fprintf(STDERR, " FAIL\n");
995 ierror += kerror;
996 }
997 #ifdef PNG_USER_MEM_SUPPORTED
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 }
1013 #ifdef PNG_USER_MEM_SUPPORTED
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;
1023 #ifdef PNG_USER_MEM_SUPPORTED
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)
1034 {
1035 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1036 fprintf(STDERR, " PASS (%lu zero samples)\n",zero_samples);
1037 #else
1038 fprintf(STDERR, " PASS\n");
1039 #endif
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 }
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 }
1053 #ifdef PNG_USER_MEM_SUPPORTED
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;
1059
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 }
1069 #ifdef PNG_USER_MEM_SUPPORTED
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 }
1081