pngtest.c 25.6 KB
Newer Older
A
Andreas Dilger 已提交
1

G
Guy Schalnat 已提交
2
/* pngtest.c - a simple test program to test libpng
3
 *
4
 * libpng 0.99d
5 6 7
 * For conditions of distribution and use, see copyright notice in png.h
 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
 * Copyright (c) 1996, 1997 Andreas Dilger
8
 * Copyright (c) 1998, Glenn Randers-Pehrson
9
 * February 8, 1998
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * This program reads in a PNG image, writes it out again, and then
 * compares the two files.  If the files are identical, this shows that
 * the basic chunk handling, filtering, and (de)compression code is working
 * properly.  It does not currently test all of the transforms, although
 * it probably should.
 *
 * The program will fail in certain legitimate cases:
 * 1) when the compression level or filter selection method is changed.
 * 2) when the chunk size is smaller than 8K.
 * 3) unknown ancillary chunks exist in the input file.
 * 4) others not listed here...
 * In these cases, it is best to check with another tool such as "pngcheck"
 * to see what the differences between the two images are.
 *
 * If a filename is given on the command-line, then this file is used
 * for the input, rather than the default "pngtest.png".  This allows
 * testing a wide variety of files easily.
 */
G
Guy Schalnat 已提交
29 30 31

#include <stdio.h>
#include <stdlib.h>
A
Andreas Dilger 已提交
32 33 34 35 36 37

/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
#ifndef PNG_DEBUG
#define PNG_DEBUG 0
#endif

G
Guy Schalnat 已提交
38 39
#include "png.h"

40 41 42 43
#ifdef PNGTEST_MEMORY_DEBUG
#include <unistd.h>
#endif

44 45
int test_one_file(PNG_CONST char *inname, PNG_CONST char *outname);

G
Guy Schalnat 已提交
46 47 48 49 50
#ifdef __TURBOC__
#include <mem.h>
#endif

/* defined so I can write to a file on gui/windowing platforms */
G
Guy Schalnat 已提交
51
/*  #define STDERR stderr  */
G
Guy Schalnat 已提交
52
#define STDERR stdout   /* for DOS */
G
Guy Schalnat 已提交
53

54 55
static int verbose = 0;

56
#if defined(PNG_NO_STDIO)
57 58 59 60 61 62 63 64 65
/* START of code to validate stdio-free compilation */
/* These copies of the default read/write functions come from pngrio.c and */
/* pngwio.c.  They allow "don't include stdio" testing of the library. */
/* This is the function which does the actual reading of data.  If you are
   not reading from a standard C stream, you should create a replacement
   read_data function and use it at run time with png_set_read_fn(), rather
   than changing the library. */
#ifndef USE_FAR_KEYWORD
static void
66 67
png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length);
static void
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
   png_size_t check;

   /* fread() returns 0 on error, so it is OK to store this in a png_size_t
    * instead of an int, which is what fread() actually returns.
    */
   check = (png_size_t)fread(data, (png_size_t)1, length,
      (FILE *)png_ptr->io_ptr);

   if (check != length)
   {
      png_error(png_ptr, "Read Error");
   }
}
G
Guy Schalnat 已提交
83
#else
84 85 86 87 88 89 90 91
/* this is the model-independent version. Since the standard I/O library
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/
 
#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)
 
92 93
static void
png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length);
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static void
png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
   int check;
   png_byte *n_data;
   FILE *io_ptr;

   /* Check if data really is near. If so, use usual code. */
   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
   io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
   if ((png_bytep)n_data == data)
   {
      check = fread(n_data, 1, length, io_ptr);
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t read, remaining, err;
      check = 0;
      remaining = length;
      do
      {
         read = MIN(NEAR_BUF_SIZE, remaining);
         err = fread(buf, (png_size_t)1, read, io_ptr);
         png_memcpy(data, buf, read); /* copy far buffer to near buffer */
         if(err != read)
            break;
         else
            check += err;
         data += read;
         remaining -= read;
      }
      while (remaining != 0);
   }
   if (check != length)
   {
      png_error(png_ptr, "read Error");
   }
}
133
#endif /* USE_FAR_KEYWORD */
G
Guy Schalnat 已提交
134

135 136
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
static void
137 138
png_default_flush(png_structp png_ptr);
static void
139 140 141 142 143 144 145 146
png_default_flush(png_structp png_ptr)
{
   FILE *io_ptr;
   io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
   if (io_ptr != NULL)
      fflush(io_ptr);
}
#endif
G
Guy Schalnat 已提交
147

148 149 150 151 152 153
/* This is the function which does the actual writing of data.  If you are
   not writing to a standard C stream, you should create a replacement
   write_data function and use it at run time with png_set_write_fn(), rather
   than changing the library. */
#ifndef USE_FAR_KEYWORD
static void
154 155
png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length);
static void
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
   png_uint_32 check;

   check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}
#else
/* this is the model-independent version. Since the standard I/O library
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/

#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)

175 176
static void
png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length);
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
static void
png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
   png_uint_32 check;
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
   FILE *io_ptr;

   /* Check if data really is near. If so, use usual code. */
   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
   io_ptr = (FILE *)CVT_PTR(png_ptr->io_ptr);
   if ((png_bytep)near_data == data)
   {
      check = fwrite(near_data, 1, length, io_ptr);
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t written, remaining, err;
      check = 0;
      remaining = length;
      do
      {
         written = MIN(NEAR_BUF_SIZE, remaining);
         png_memcpy(buf, data, written); /* copy far buffer to near buffer */
         err = fwrite(buf, 1, written, io_ptr);
         if (err != written)
            break;
         else
            check += err;
         data += written;
         remaining -= written;
      }
      while (remaining != 0);
   }
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}

217
#endif /* USE_FAR_KEYWORD */
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

/* This function is called when there is a warning, but the library thinks
 * it can continue anyway.  Replacement functions don't have to do anything
 * here if you don't want to.  In the default configuration, png_ptr is
 * not used, but it is passed in case it may be useful.
 */
static void
png_default_warning(png_structp png_ptr, png_const_charp message)
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
   if (png_ptr != NULL && png_ptr->error_ptr != NULL)
      name = png_ptr->error_ptr;
   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
}

/* This is the default error handling function.  Note that replacements for
 * this function MUST NOT RETURN, or the program will likely crash.  This
 * function is used by default, or if the program supplies NULL for the
 * error function pointer in png_set_error_fn().
 */
static void
png_default_error(png_structp png_ptr, png_const_charp message)
{
   png_default_warning(png_ptr, message);
   /* We can return because png_error calls the default handler which is
    * actually ok in this case. */
}
245
#endif /* PNG_NO_STDIO */
246 247
/* END of code to validate stdio-free compilation */

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
/* START of code to validate memory allocation and deallocation */
#ifdef PNGTEST_MEMORY_DEBUG
/* Borland DOS special memory handler */
#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
ERROR - memory debugging is not supported on this platform
#else

/* Allocate memory.  For reasonable files, size should never exceed
   64K.  However, zlib may allocate more then 64K if you don't tell
   it not to.  See zconf.h and png.h for more information.  zlib does
   need to allocate exactly 64K, so whatever you call here must
   have the ability to do that.

   This piece of code can be compiled to validate max 64K allocations
   by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
typedef struct memory_information {
   png_uint_32                    size;
   png_voidp                      pointer;
   struct memory_information FAR *next;
} memory_information;
typedef memory_information FAR *memory_infop;

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;

extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr,
   png_uint_32 size));
extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr,
   png_voidp ptr));

png_voidp
png_malloc(png_structp png_ptr, png_uint_32 size) {
   if (png_ptr == NULL) {
      fprintf(STDERR, "NULL pointer to memory allocator\n");
283
      return (NULL);
284 285
   }
   if (size == 0)
286
      return (png_voidp)(NULL);
287 288 289 290 291 292 293 294 295 296 297 298 299 300

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
      memory_infop pinfo = png_debug_malloc(png_ptr, sizeof *pinfo);
      pinfo->size = size;
      current_allocation += size;
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
      pinfo->pointer = png_debug_malloc(png_ptr, size);
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
      png_memset(pinfo->pointer, 0xdd, pinfo->size);
301
      return (png_voidp)(pinfo->pointer);
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
void
png_free(png_structp png_ptr, png_voidp ptr)
{
   if (png_ptr == NULL)
      fprintf(STDERR, "NULL pointer to memory allocator\n");
   if (ptr == 0) {
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
      memory_infop FAR *ppinfo = &pinformation;
      for (;;) {
         memory_infop pinfo = *ppinfo;
         if (pinfo->pointer == ptr) {
            *ppinfo = pinfo->next;
            current_allocation -= pinfo->size;
            if (current_allocation < 0)
               fprintf(STDERR, "Duplicate free of memory\n");
            /* We must free the list element too, but first kill
               the memory which is to be freed. */
            memset(ptr, 0x55, pinfo->size);
            png_debug_free(png_ptr, pinfo);
            break;
         }
         if (pinfo->next == NULL) {
            fprintf(STDERR, "Pointer %x not found\n", ptr);
            break;
         }
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
   png_debug_free(png_ptr, ptr);
}
#endif /* Not Borland DOS special memory handler */
#endif
/* END of code to test memory allocation/deallocation */

349
/* Test one file */
350
int test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
351
{
352
   static FILE *fpin, *fpout;  /* "static" prevents setjmp corruption */
A
Andreas Dilger 已提交
353 354
   png_structp read_ptr, write_ptr;
   png_infop read_info_ptr, write_info_ptr, end_info_ptr;
G
Guy Schalnat 已提交
355
   png_bytep row_buf;
G
Guy Schalnat 已提交
356
   png_uint_32 y;
A
Andreas Dilger 已提交
357 358 359
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
A
Andreas Dilger 已提交
360 361 362
#ifdef USE_FAR_KEYWORD
   jmp_buf jmpbuf;
#endif   
363 364
   
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
365

366
   row_buf = (png_bytep)NULL;
G
Guy Schalnat 已提交
367

A
Andreas Dilger 已提交
368
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
369 370
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
371
      return (1);
G
Guy Schalnat 已提交
372 373
   }

A
Andreas Dilger 已提交
374
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
375
   {
G
Guy Schalnat 已提交
376
      fprintf(STDERR, "Could not open output file %s\n", outname);
G
Guy Schalnat 已提交
377
      fclose(fpin);
378
      return (1);
G
Guy Schalnat 已提交
379 380
   }

A
Andreas Dilger 已提交
381
   png_debug(0, "Allocating read and write structures\n");
A
Andreas Dilger 已提交
382
   read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
A
Andreas Dilger 已提交
383
      (png_error_ptr)NULL, (png_error_ptr)NULL);
384
#if defined(PNG_NO_STDIO)
385 386
   png_set_error_fn(read_ptr, (png_voidp)inname, png_default_error,
       png_default_warning);
387
#endif
A
Andreas Dilger 已提交
388
   write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
G
Guy Schalnat 已提交
389
      (png_error_ptr)NULL, (png_error_ptr)NULL);
390
#if defined(PNG_NO_STDIO)
391 392
   png_set_error_fn(write_ptr, (png_voidp)inname, png_default_error,
       png_default_warning);
393
#endif
A
Andreas Dilger 已提交
394 395
   png_debug(0, "Allocating read_info, write_info and end_info structures\n");
   read_info_ptr = png_create_info_struct(read_ptr);
396
   write_info_ptr = png_create_info_struct(write_ptr);
A
Andreas Dilger 已提交
397
   end_info_ptr = png_create_info_struct(read_ptr);
G
Guy Schalnat 已提交
398

A
Andreas Dilger 已提交
399
   png_debug(0, "Setting jmpbuf for read struct\n");
A
Andreas Dilger 已提交
400 401 402
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmpbuf))
#else
G
Guy Schalnat 已提交
403
   if (setjmp(read_ptr->jmpbuf))
A
Andreas Dilger 已提交
404
#endif
G
Guy Schalnat 已提交
405
   {
406
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
A
Andreas Dilger 已提交
407 408
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
G
Guy Schalnat 已提交
409 410
      fclose(fpin);
      fclose(fpout);
411
      return (1);
G
Guy Schalnat 已提交
412
   }
A
Andreas Dilger 已提交
413 414

   png_debug(0, "Setting jmpbuf for write struct\n");
A
Andreas Dilger 已提交
415 416 417 418
#ifdef USE_FAR_KEYWORD
   png_memcpy(read_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
   if (setjmp(jmpbuf))
#else
G
Guy Schalnat 已提交
419
   if (setjmp(write_ptr->jmpbuf))
A
Andreas Dilger 已提交
420
#endif
G
Guy Schalnat 已提交
421
   {
422
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
423 424
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
G
Guy Schalnat 已提交
425 426
      fclose(fpin);
      fclose(fpout);
427
      return (1);
G
Guy Schalnat 已提交
428
   }
A
Andreas Dilger 已提交
429

A
Andreas Dilger 已提交
430 431 432
#ifdef USE_FAR_KEYWORD
   png_memcpy(write_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
#endif
A
Andreas Dilger 已提交
433
   png_debug(0, "Initializing input and output streams\n");
434
#if !defined(PNG_NO_STDIO)
G
Guy Schalnat 已提交
435 436
   png_init_io(read_ptr, fpin);
   png_init_io(write_ptr, fpout);
437 438 439 440 441 442 443 444 445
#else
   png_set_read_fn(read_ptr, (png_voidp)fpin, png_default_read_data);
   png_set_write_fn(write_ptr, (png_voidp)fpout,  png_default_write_data,
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
      png_default_flush);
#else
      NULL);
#endif
#endif
G
Guy Schalnat 已提交
446

A
Andreas Dilger 已提交
447 448
   png_debug(0, "Reading info struct\n");
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
449

A
Andreas Dilger 已提交
450 451 452
   png_debug(0, "Transferring info struct\n");
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
453

A
Andreas Dilger 已提交
454 455 456 457
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
458
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
459
            color_type, interlace_type, compression_type, filter_type);
460 461 462
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
463 464 465
      }
   }
#if defined(PNG_READ_bKGD_SUPPORTED) && defined(PNG_WRITE_bKGD_SUPPORTED)
G
Guy Schalnat 已提交
466
   {
A
Andreas Dilger 已提交
467 468 469 470 471 472
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
G
Guy Schalnat 已提交
473
   }
A
Andreas Dilger 已提交
474 475 476 477
#endif
#if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED)
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
G
Guy Schalnat 已提交
478

A
Andreas Dilger 已提交
479 480 481 482 483 484 485 486 487
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
         &red_y, &green_x, &green_y, &blue_x, &blue_y))
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
      }
   }
#endif
#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED)
G
Guy Schalnat 已提交
488
   {
A
Andreas Dilger 已提交
489 490 491 492 493 494
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
      {
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
      }
G
Guy Schalnat 已提交
495
   }
496 497 498
#endif
#if defined(PNG_READ_sRGB_SUPPORTED) && defined(PNG_WRITE_sRGB_SUPPORTED)
   {
499
      int intent;
500 501 502 503 504 505

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
      {
         png_set_sRGB(write_ptr, write_info_ptr, intent);
      }
   }
A
Andreas Dilger 已提交
506 507
#endif
#if defined(PNG_READ_hIST_SUPPORTED) && defined(PNG_WRITE_hIST_SUPPORTED)
G
Guy Schalnat 已提交
508
   {
A
Andreas Dilger 已提交
509 510 511 512 513 514
      png_uint_16p hist;

      if (png_get_hIST(read_ptr, read_info_ptr, &hist))
      {
         png_set_hIST(write_ptr, write_info_ptr, hist);
      }
G
Guy Schalnat 已提交
515
   }
A
Andreas Dilger 已提交
516 517 518 519 520
#endif
#if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED)
   {
      png_uint_32 offset_x, offset_y;
      int unit_type;
G
Guy Schalnat 已提交
521

A
Andreas Dilger 已提交
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
      if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
#if defined(PNG_READ_pCAL_SUPPORTED) && defined(PNG_WRITE_pCAL_SUPPORTED)
   {
      png_charp purpose, units;
      png_charpp params;
      png_int_32 X0, X1;
      int type, nparams;

      if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
         &nparams, &units, &params))
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED)
   {
      png_uint_32 res_x, res_y;
      int unit_type;

      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
      {
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
      }
   }
#endif
   {
      png_colorp palette;
      int num_palette;

      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
      {
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
      }
   }
#if defined(PNG_READ_sBIT_SUPPORTED) && defined(PNG_WRITE_sBIT_SUPPORTED)
G
Guy Schalnat 已提交
564
   {
A
Andreas Dilger 已提交
565 566 567
      png_color_8p sig_bit;

      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
G
Guy Schalnat 已提交
568
      {
A
Andreas Dilger 已提交
569 570 571
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
      }
   }
G
Guy Schalnat 已提交
572
#endif
A
Andreas Dilger 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) || \
    (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED))
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
         png_debug1(0, "Handling %d tEXt/zTXt chunks\n", num_text);
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
#if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED)
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
      }
   }
#endif
#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED)
   {
      png_bytep trans;
      int num_trans;
      png_color_16p trans_values;

      if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
         &trans_values))
      {
         png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
            trans_values);
      }
   }
#endif

   png_debug(0, "\nWriting info struct\n");
   png_write_info(write_ptr, write_info_ptr);

614
   png_debug(0, "\nAllocating row buffer \n");
A
Andreas Dilger 已提交
615 616 617 618 619 620 621 622 623
   row_buf = (png_bytep)png_malloc(read_ptr, 
      png_get_rowbytes(read_ptr, read_info_ptr));
   if (row_buf == NULL)
   {
      fprintf(STDERR, "No memory to allocate row buffer\n");
      png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL);
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
      fclose(fpin);
      fclose(fpout);
624
      return (1);
A
Andreas Dilger 已提交
625
   }
626
   png_debug(0, "Writing row data\n");
A
Andreas Dilger 已提交
627 628 629 630 631 632

   num_pass = png_set_interlace_handling(read_ptr);
   png_set_interlace_handling(write_ptr);

   for (pass = 0; pass < num_pass; pass++)
   {
633
      png_debug1(0, "Writing row data for pass %d\n",pass);
A
Andreas Dilger 已提交
634 635 636
      for (y = 0; y < height; y++)
      {
         png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
G
Guy Schalnat 已提交
637
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
G
Guy Schalnat 已提交
638 639 640
      }
   }

A
Andreas Dilger 已提交
641 642 643
   png_debug(0, "Reading and writing end_info data\n");
   png_read_end(read_ptr, end_info_ptr);
   png_write_end(write_ptr, end_info_ptr);
644 645 646 647 648 649 650 651 652 653 654
 
#ifdef PNG_EASY_ACCESS_SUPPORTED
   if(verbose)
   {
      png_uint_32 iwidth, iheight;
      iwidth = png_get_image_width(write_ptr, write_info_ptr);
      iheight = png_get_image_height(write_ptr, write_info_ptr);
      fprintf(STDERR, "Image width = %lu, height = %lu\n",
         iwidth, iheight);
   }
#endif
G
Guy Schalnat 已提交
655

A
Andreas Dilger 已提交
656
   png_debug(0, "Destroying data structs\n");
657
   png_free(read_ptr, row_buf);
A
Andreas Dilger 已提交
658 659
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
G
Guy Schalnat 已提交
660 661 662 663

   fclose(fpin);
   fclose(fpout);

A
Andreas Dilger 已提交
664 665
   png_debug(0, "Opening files for comparison\n");
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
666
   {
G
Guy Schalnat 已提交
667
      fprintf(STDERR, "Could not find file %s\n", inname);
668
      return (1);
G
Guy Schalnat 已提交
669 670
   }

A
Andreas Dilger 已提交
671
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
672
   {
G
Guy Schalnat 已提交
673
      fprintf(STDERR, "Could not find file %s\n", outname);
G
Guy Schalnat 已提交
674
      fclose(fpin);
675
      return (1);
G
Guy Schalnat 已提交
676
   }
A
Andreas Dilger 已提交
677

G
Guy Schalnat 已提交
678 679
   while (1)
   {
A
Andreas Dilger 已提交
680
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
681

A
Andreas Dilger 已提交
682 683
      num_in = fread(inbuf, 1, 1, fpin);
      num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
684 685 686

      if (num_in != num_out)
      {
G
Guy Schalnat 已提交
687 688
         fprintf(STDERR, "Files %s and %s are of a different size\n",
                 inname, outname);
G
Guy Schalnat 已提交
689 690
         fclose(fpin);
         fclose(fpout);
691
         return (1);
G
Guy Schalnat 已提交
692 693 694 695 696
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
697
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
698
      {
G
Guy Schalnat 已提交
699
         fprintf(STDERR, "Files %s and %s are different\n", inname, outname);
G
Guy Schalnat 已提交
700 701
         fclose(fpin);
         fclose(fpout);
702
         return (1);
G
Guy Schalnat 已提交
703 704 705 706 707
      }
   }

   fclose(fpin);
   fclose(fpout);
G
Guy Schalnat 已提交
708

709
   return (0);
G
Guy Schalnat 已提交
710
}
G
Guy Schalnat 已提交
711

712 713 714 715 716
/* input and output filenames */
#ifdef RISCOS
PNG_CONST char *inname = "pngtest_png";
PNG_CONST char *outname = "pngout_png";
#else
717 718
static char *inname = "pngtest.png";
static char *outname = "pngout.png";
719 720 721 722 723 724 725 726 727
#endif

int
main(int argc, char *argv[])
{
   int multiple = 0;
   int ierror = 0;

   fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
728 729 730 731 732 733 734 735 736 737 738 739 740
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);

   /* Do some consistency checking on the memory allocation settings, I'm
      not sure this matters, but it is nice to know, the first of these
      tests should be impossible because of the way the macros are set
      in pngconf.h */
   #if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
   #endif
   /* I think the following can happen. */
   #if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
   #endif
741 742 743 744 745 746 747 748 749 750 751 752

   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
   {
      fprintf(STDERR,
         "Warning: versions are different between png.h and png.c\n");
      fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
      fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
      ++ierror;
   }

   if (argc > 1)
   {
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
      if (strcmp(argv[1], "-m") == 0)
         multiple = 1;
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
      }
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
         inname = argv[2];
      }
      else
         inname = argv[1];
768 769
   }

770 771
   if (!multiple && argc == 3+verbose)
     outname = argv[2+verbose];
772

773
   if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
774
   {
775 776
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
777
        argv[0], argv[0]);
778 779 780 781
     fprintf(STDERR,
       "  reads/writes one PNG file (without -m) or multiple files (-m)\n");
     fprintf(STDERR,
       "  with -m %s is used as a temporary file\n", outname);
782 783 784 785 786 787
     exit(1);
   }

   if (multiple)
   {
      int i;
788 789 790
#ifdef PNGTEST_MEMORY_DEBUG
      int allocation_now = current_allocation;
#endif
791
      for (i=2; i<argc; ++i)
792
      {
793 794 795
         int kerror;
         fprintf(STDERR, "Testing %s:",argv[i]);
         kerror = test_one_file(argv[i], outname);
796 797
         if (kerror == 0) 
            fprintf(STDERR, " PASS\n");
798 799 800 801
         else {
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
            }
802 803 804 805 806 807 808 809 810 811 812 813 814
#ifdef PNGTEST_MEMORY_DEBUG
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
               current_allocation-allocation_now);
         if (current_allocation != 0) {
            memory_infop pinfo = pinformation;

            fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
               current_allocation);
            while (pinfo != NULL) {
               fprintf(STDERR, " %d bytes at %x\n", pinfo->size, pinfo->pointer);
               pinfo = pinfo->next;
               }
815
         }
816 817 818 819 820 821
#endif
      }
#ifdef PNGTEST_MEMORY_DEBUG
         fprintf(STDERR, "Maximum memory allocation: %d bytes\n",
            maximum_allocation);
#endif
822 823 824
   }
   else
   {
825 826 827
      int i;
      for (i=0; i<3; ++i) {
         int kerror;
828 829 830 831 832
#ifdef PNGTEST_MEMORY_DEBUG
         int allocation_now = current_allocation;
#endif
         if (i == 0 || verbose == 1 || ierror != 0)
            fprintf(STDERR, "Testing %s:",inname);
833
         kerror = test_one_file(inname, outname);
834 835 836 837 838 839 840 841
         if(kerror == 0)
         {
            if(verbose == 1 || i == 2) fprintf(STDERR, " PASS\n");
         }
         else
         {
            if(verbose == 0 && i != 2)
               fprintf(STDERR, "Testing %s:",inname);
842 843
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
         }
#ifdef PNGTEST_MEMORY_DEBUG
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
               current_allocation-allocation_now);
         if (current_allocation != 0) {
             memory_infop pinfo = pinformation;
   
             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
                current_allocation);
             while (pinfo != NULL) {
                fprintf(STDERR, " %d bytes at %x\n", pinfo->size, pinfo->pointer);
                pinfo = pinfo->next;
             }
          }
#endif
860
       }
861 862 863 864
#ifdef PNGTEST_MEMORY_DEBUG
       fprintf(STDERR, "Maximum memory allocation: %d bytes\n",
          maximum_allocation);
#endif
865 866 867 868 869 870
   }

   if (ierror == 0)
      fprintf(STDERR, "libpng passes test\n");
   else
      fprintf(STDERR, "libpng FAILS test\n");
871
   return (int)(ierror != 0);
872
}