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