example.c 37.7 KB
Newer Older
1

2 3
#if 0 /* in case someone actually tries to compile this */

4
/* example.c - an example of using libpng
5
 * Last changed in libpng 1.5.6 [November 3, 2011]
6
 * This file has been placed in the public domain by the authors.
7
 * Maintained 1998-2011 Glenn Randers-Pehrson
8 9 10
 * Maintained 1996, 1997 Andreas Dilger)
 * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
 */
G
Guy Schalnat 已提交
11

A
Andreas Dilger 已提交
12
/* This is an example of how to use libpng to read and write PNG files.
13
 * The file libpng-manual.txt is much more verbose then this.  If you have not
14
 * read it, do so first.  This was designed to be a starting point of an
15 16
 * implementation.  This is not officially part of libpng, is hereby placed
 * in the public domain, and therefore does not require a copyright notice.
17 18 19 20
 *
 * This file does not currently compile, because it is missing certain
 * parts, like allocating memory to hold an image.  You will have to
 * supply these parts to get it to compile.  For an example of a minimal
21 22
 * working PNG reader/writer, see pngtest.c, included in this distribution;
 * see also the programs in the contrib directory.
23
 */
G
Guy Schalnat 已提交
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
/* The simple, but restricted, approach to reading a PNG file or data stream
 * just requires two function calls, as in the following complete program.
 * Writing a file just needs one function call, so long as the data has an
 * appropriate layout.
 *
 * The following code reads PNG image data from a file and writes it, in a
 * potentially new format, to a new file.  While this code will compile there is
 * minimal (insufficient) error checking; for a more realistic version look at
 * contrib/examples/pngtopng.c
 */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <png.h>

int main(int argc, const char **argv)
{
   if (argc == 3)
   {
      png_image image; /* The control structure used by libpng */

      /* Initialize the 'png_image' structure. */
      memset(&image, 0, sizeof image);

      /* The first argument is the file to read: */
      if (png_image_begin_read_from_file(&image, argv[1]))
      {
         png_bytep buffer;

         /* Set the format in which to read the PNG file; this code chooses a
          * simple sRGB format with a non-associated alpha channel, adequate to
          * store most images.
          */
         image.format = PNG_FORMAT_RGBA;

         /* Now allocate enough memory to hold the image in this format; the
          * PNG_IMAGE_SIZE macro uses the information about the image (width,
          * height and format) stored in 'image'.
          */
         buffer = malloc(PNG_IMAGE_SIZE(image));

         /* If enough memory was available read the image in the desired format
          * then write the result out to the new file.  'background' is not
          * necessary when reading the image because the alpha channel is
          * preserved; if it were to be removed, for example if we requested
          * PNG_FORMAT_RGB, then either a solid background color would have to
          * be supplied or the output buffer would have to be initialized to the
          * actual background of the image.
          *
          * The final argument to png_image_finish_read is the 'row_stride' -
          * this is the number of components allocated for the image in each
          * row.  It has to be at least as big as the value returned by
          * PNG_IMAGE_ROW_STRIDE, but if you just allocate space for the
          * default, minimum, size using PNG_IMAGE_SIZE as above you can pass
          * zero.
          */
         if (buffer != NULL &&
            png_image_finish_read(&image, NULL/*background*/, buffer,
               0/*row_stride*/))
         {
            /* Now write the image out to the second argument.  In the write
             * call 'convert_to_8bit' allows 16-bit data to be squashed down to
             * 8 bits; this isn't necessary here because the original read was
             * to the 8-bit format.
             */
            if (png_image_write_to_file(&image, argv[2], 0/*convert_to_8bit*/,
               buffer, 0/*row_stride*/))
            {
               /* The image has been written successfully. */
               exit(0);
            }
         }
      }

      /* Something went wrong reading or writing the image.  libpng stores a
       * textual message in the 'png_image' structure:
       */
      fprintf(stderr, "pngtopng: error: %s\n", image.message);
      exit (1);
   }

   fprintf(stderr, "pngtopng: usage: pngtopng input-file output-file\n");
   exit(1);
}

/* That's it ;-)  Of course you probably want to do more with PNG files than
 * just converting them all to 32-bit RGBA PNG files; you can do that between
 * the call to png_image_finish_read and png_image_write_to_file.  You can also
 * ask for the image data to be presented in a number of different formats.  You
 * do this by simply changing the 'format' parameter set before allocating the
 * buffer.
 *
 * The format parameter consists of five flags that define various aspects of
 * the image, you can simply add these together to get the format or you can use
 * one of the predefined macros from png.h (as above):
 *
 * PNG_FORMAT_FLAG_COLOR: if set the image will have three color components per
 *    pixel (red, green and blue), if not set the image will just have one
 *    luminance (grayscale) component.
 *
 * PNG_FORMAT_FLAG_ALPHA: if set each pixel in the image will have an additional
 *    alpha value; a linear value that describes the degree the image pixel
 *    covers (overwrites) the contents of the existing pixel on the display.
 *
 * PNG_FORMAT_FLAG_LINEAR: if set the components of each pixel will be returned
 *    as a series of 16-bit linear values, if not set the components will be
 *    returned as a series of 8-bit values encoded according to the 'sRGB'
 *    standard.  The 8-bit format is the normal format for images intended for
 *    direct display, because almost all display devices do the inverse of the
 *    sRGB transformation to the data they receive.  The 16-bit format is more
 *    common for scientific data and image data that must be further processed;
 *    because it is linear simple math can be done on the component values.
 *    Regardless of the setting of this flag the alpha channel is always linear,
 *    although it will be 8 bits or 16 bits wide as specified by the flag.
 *
 * PNG_FORMAT_FLAG_BGR: if set the components of a color pixel will be returned
 *    in the order blue, then green, then red.  If not set the pixel components
 *    are in the order red, then green, then blue.
 *
 * PNG_FORMAT_FLAG_AFIRST: if set the alpha channel (if present) precedes the
 *    color or grayscale components.  If not set the alpha channel follows the
 *    components.
 *
 * You do not have to read directly from a file.  You can read from memory or,
 * on systems that support it, from a <stdio.h> FILE*.  This is controlled by
 * the particular png_image_read_from_ function you call at the start.  Likewise
 * on write you can write to a FILE* if your system supports it.  Check the
 * macro PNG_STDIO_SUPPORTED to see if stdio support has been included in your
 * libpng build.
 *
 * If you read 16-bit (PNG_FORMAT_FLAG_LINEAR) data you may need to write it in
 * the 8-bit format for display.  You do this by setting the convert_to_8bit
 * flag to 'true'.
 *
 * Don't repeatedly convert between the 8-bit and 16-bit forms.  There is
 * significant data loss when 16-bit data is converted to the 8-bit encoding and
 * the current libpng implementation of convertion to 16-bit is also
 * significantly lossy.  The latter will be fixed in the future, but the former
 * is unavoidable - the 8-bit format just doesn't have enough resolution.
 */
166

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
/* If your program needs more information from the PNG data it reads, or if you
 * need to do more complex transformations, or minimise transformations, on the
 * data you read, then you must use one of the several lower level libpng
 * interfaces.
 *
 * All these interfaces require that you do your own error handling - your
 * program must be able to arrange for control to return to your own code any
 * time libpng encounters a problem.  There are several ways to do this, but the
 * standard way is to use the ANSI-C (C90) <setjmp.h> interface to establish a
 * return point within your own code.  You must do this if you do not use the
 * simplified interface (above).
 *
 * The first step is to include the header files you need, including the libpng
 * header file.  Include any standard headers and feature test macros your
 * program requires before including png.h:
 */
#include <png.h>
G
Guy Schalnat 已提交
184

185 186 187 188 189 190 191
 /* The png_jmpbuf() macro, used in error handling, became available in
  * libpng version 1.0.6.  If you want to be able to run your code with older
  * versions of libpng, you must define the macro yourself (but only if it
  * is not already defined by libpng!).
  */

#ifndef png_jmpbuf
192
#  define png_jmpbuf(png_ptr) ((png_ptr)->png_jmpbuf)
193 194
#endif

195 196 197 198 199
/* Check to see if a file is a PNG file using png_sig_cmp().  png_sig_cmp()
 * returns zero if the image is a PNG and nonzero if it isn't a PNG.
 *
 * The function check_if_png() shown here, but not used, returns nonzero (true)
 * if the file can be opened and is a PNG, 0 (false) otherwise.
200 201 202 203 204 205 206 207 208 209 210 211
 *
 * If this call is successful, and you are going to keep the file open,
 * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
 * you have created the png_ptr, so that libpng knows your application
 * has read that many bytes from the start of the file.  Make sure you
 * don't call png_set_sig_bytes() with more than 8 bytes read or give it
 * an incorrect number of bytes read, or you will either have read too
 * many bytes (your fault), or you are telling libpng to read the wrong
 * number of magic bytes (also your fault).
 *
 * Many applications already read the first 2 or 4 bytes from the start
 * of the image to determine the file type, so it would be easiest just
212
 * to pass the bytes to png_sig_cmp() or even skip that if you know
213 214
 * you have a PNG file, and call png_set_sig_bytes().
 */
A
Andreas Dilger 已提交
215 216
#define PNG_BYTES_TO_CHECK 4
int check_if_png(char *file_name, FILE **fp)
G
Guy Schalnat 已提交
217
{
A
Andreas Dilger 已提交
218
   char buf[PNG_BYTES_TO_CHECK];
G
Guy Schalnat 已提交
219

A
Andreas Dilger 已提交
220
   /* Open the prospective PNG file. */
221
   if ((*fp = fopen(file_name, "rb")) == NULL)
G
Guy Schalnat 已提交
222 223
      return 0;

224
   /* Read in some of the signature bytes */
A
Andreas Dilger 已提交
225
   if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
G
Guy Schalnat 已提交
226 227
      return 0;

228 229 230
   /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
      Return nonzero (true) if they match */

231
   return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
G
Guy Schalnat 已提交
232 233
}

A
Andreas Dilger 已提交
234
/* Read a PNG file.  You may want to return an error code if the read
235 236 237 238 239
 * fails (depending upon the failure).  There are two "prototypes" given
 * here - one where we are given the filename, and we need to open the
 * file, and the other where we are given an open file (possibly with
 * some or all of the magic bytes read - see comments above).
 */
240
#ifdef open_file /* prototype 1 */
A
Andreas Dilger 已提交
241
void read_png(char *file_name)  /* We need to open the file */
G
Guy Schalnat 已提交
242
{
G
Guy Schalnat 已提交
243
   png_structp png_ptr;
G
Guy Schalnat 已提交
244
   png_infop info_ptr;
A
Andreas Dilger 已提交
245 246 247
   unsigned int sig_read = 0;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
A
Andreas Dilger 已提交
248
   FILE *fp;
G
Guy Schalnat 已提交
249

A
Andreas Dilger 已提交
250
   if ((fp = fopen(file_name, "rb")) == NULL)
251
      return (ERROR);
252

253
#else no_open_file /* prototype 2 */
254
void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
A
Andreas Dilger 已提交
255 256 257
{
   png_structp png_ptr;
   png_infop info_ptr;
A
Andreas Dilger 已提交
258 259
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
260
#endif no_open_file /* Only use one prototype! */
G
Guy Schalnat 已提交
261

G
Guy Schalnat 已提交
262
   /* Create and initialize the png_struct with the desired error handler
A
Andreas Dilger 已提交
263 264 265 266 267
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  REQUIRED
    */
G
Guy Schalnat 已提交
268
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
269
      png_voidp user_error_ptr, user_error_fn, user_warning_fn);
G
Guy Schalnat 已提交
270

A
Andreas Dilger 已提交
271
   if (png_ptr == NULL)
G
Guy Schalnat 已提交
272 273
   {
      fclose(fp);
274
      return (ERROR);
G
Guy Schalnat 已提交
275 276
   }

A
Andreas Dilger 已提交
277
   /* Allocate/initialize the memory for image information.  REQUIRED. */
278
   info_ptr = png_create_info_struct(png_ptr);
A
Andreas Dilger 已提交
279
   if (info_ptr == NULL)
G
Guy Schalnat 已提交
280 281
   {
      fclose(fp);
282
      png_destroy_read_struct(&png_ptr, NULL, NULL);
283
      return (ERROR);
G
Guy Schalnat 已提交
284 285
   }

A
Andreas Dilger 已提交
286 287 288 289
   /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */
290 291

   if (setjmp(png_jmpbuf(png_ptr)))
G
Guy Schalnat 已提交
292
   {
G
Guy Schalnat 已提交
293
      /* Free all of the memory associated with the png_ptr and info_ptr */
294
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
G
Guy Schalnat 已提交
295 296
      fclose(fp);
      /* If we get here, we had a problem reading the file */
297
      return (ERROR);
G
Guy Schalnat 已提交
298 299
   }

A
Andreas Dilger 已提交
300
   /* One of the following I/O initialization methods is REQUIRED */
301
#ifdef streams /* PNG file I/O method 1 */
A
Andreas Dilger 已提交
302
   /* Set up the input control if you are using standard C streams */
G
Guy Schalnat 已提交
303 304
   png_init_io(png_ptr, fp);

305
#else no_streams /* PNG file I/O method 2 */
A
Andreas Dilger 已提交
306
   /* If you are using replacement read functions, instead of calling
307 308
    * png_init_io() here you would call:
    */
G
Guy Schalnat 已提交
309 310
   png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
   /* where user_io_ptr is a structure you want available to the callbacks */
311
#endif no_streams /* Use only one I/O method! */
G
Guy Schalnat 已提交
312

A
Andreas Dilger 已提交
313
   /* If we have already read some of the signature */
314
   png_set_sig_bytes(png_ptr, sig_read);
A
Andreas Dilger 已提交
315

316 317 318 319 320
#ifdef hilevel
   /*
    * If you have enough memory to read in the entire image at once,
    * and you need to specify only transforms that can be controlled
    * with one of the PNG_TRANSFORM_* bits (this presently excludes
321
    * quantizing, filling, setting background, and doing gamma
322 323 324
    * adjustment), then you can read the entire image (including
    * pixels) into the info structure with this call:
    */
325
   png_read_png(png_ptr, info_ptr, png_transforms, NULL);
326

327 328 329
#else
   /* OK, you're doing it the hard way, with the lower-level functions */

A
Andreas Dilger 已提交
330 331 332
   /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk).  REQUIRED
    */
G
Guy Schalnat 已提交
333
   png_read_info(png_ptr, info_ptr);
G
Guy Schalnat 已提交
334

A
Andreas Dilger 已提交
335
   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
336
       &interlace_type, NULL, NULL);
A
Andreas Dilger 已提交
337

338 339 340 341 342
   /* Set up the data transformations you want.  Note that these are all
    * optional.  Only call them if you want/need them.  Many of the
    * transformations only work on specific types of images, and many
    * are mutually exclusive.
    */
A
Andreas Dilger 已提交
343

344 345 346 347
   /* Tell libpng to strip 16 bit/color files down to 8 bits/color.
    * Use accurate scaling if it's available, otherwise just chop off the
    * low byte.
    */
348
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
349
    png_set_scale_16(png_ptr);
350
#else
351
   png_set_strip_16(png_ptr);
352
#endif
A
Andreas Dilger 已提交
353

354
   /* Strip alpha bytes from the input data without combining with the
355 356
    * background (not recommended).
    */
A
Andreas Dilger 已提交
357 358
   png_set_strip_alpha(png_ptr);

359
   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
A
Andreas Dilger 已提交
360 361 362 363
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   png_set_packing(png_ptr);

364
   /* Change the order of packed pixels to least significant bit first
A
Andreas Dilger 已提交
365 366
    * (not useful if you are using png_set_packing). */
   png_set_packswap(png_ptr);
G
Guy Schalnat 已提交
367

368
   /* Expand paletted colors into true RGB triplets */
A
Andreas Dilger 已提交
369
   if (color_type == PNG_COLOR_TYPE_PALETTE)
370
      png_set_palette_to_rgb(png_ptr);
G
Guy Schalnat 已提交
371

372
   /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
A
Andreas Dilger 已提交
373
   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
374
      png_set_expand_gray_1_2_4_to_8(png_ptr);
G
Guy Schalnat 已提交
375

376 377 378
   /* Expand paletted or RGB images with transparency to full alpha channels
    * so the data will be available as RGBA quartets.
    */
A
Andreas Dilger 已提交
379
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
380
      png_set_tRNS_to_alpha(png_ptr);
G
Guy Schalnat 已提交
381

A
Andreas Dilger 已提交
382 383 384 385 386 387
   /* Set the background color to draw transparent and alpha images over.
    * It is possible to set the red, green, and blue components directly
    * for paletted images instead of supplying a palette index.  Note that
    * even if the PNG file supplies a background, you are not required to
    * use it - you should use the (solid) application background if it has one.
    */
G
Guy Schalnat 已提交
388

389
   png_color_16 my_background, *image_background;
G
Guy Schalnat 已提交
390

391 392
   if (png_get_bKGD(png_ptr, info_ptr, &image_background))
      png_set_background(png_ptr, image_background,
G
Guy Schalnat 已提交
393
                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
G
Guy Schalnat 已提交
394 395
   else
      png_set_background(png_ptr, &my_background,
G
Guy Schalnat 已提交
396
                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
G
Guy Schalnat 已提交
397

398 399 400
   /* Some suggestions as to how to get a screen gamma value
    *
    * Note that screen gamma is the display_exponent, which includes
401 402
    * the CRT_exponent and any correction for viewing conditions
    */
A
Andreas Dilger 已提交
403 404 405 406 407
   if (/* We have a user-defined screen gamma value */)
   {
      screen_gamma = user-defined screen_gamma;
   }
   /* This is one way that applications share the same screen gamma value */
408
   else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
A
Andreas Dilger 已提交
409 410 411 412
   {
      screen_gamma = atof(gamma_str);
   }
   /* If we don't have another value */
G
Guy Schalnat 已提交
413
   else
A
Andreas Dilger 已提交
414
   {
415
      screen_gamma = 2.2;  /* A good guess for a PC monitor in a dimly
416
                              lit room */
A
Andreas Dilger 已提交
417 418
      screen_gamma = 1.7 or 1.0;  /* A good guess for Mac systems */
   }
G
Guy Schalnat 已提交
419

420
   /* Tell libpng to handle the gamma conversion for you.  The final call
A
Andreas Dilger 已提交
421 422 423 424
    * is a good guess for PC generated images, but it should be configurable
    * by the user at run time by the user.  It is strongly suggested that
    * your application support gamma correction.
    */
425 426 427

   int intent;

428
   if (png_get_sRGB(png_ptr, info_ptr, &intent))
429
      png_set_gamma(png_ptr, screen_gamma, 0.45455);
430 431 432
   else
   {
      double image_gamma;
433
      if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
434 435
         png_set_gamma(png_ptr, screen_gamma, image_gamma);
      else
436 437
         png_set_gamma(png_ptr, screen_gamma, 0.45455);
   }
G
Guy Schalnat 已提交
438

439 440
#ifdef PNG_READ_QUANTIZE_SUPPORTED
   /* Quantize RGB files down to 8 bit palette or reduce palettes
441 442
    * to the number of colors available on your screen.
    */
A
Andreas Dilger 已提交
443
   if (color_type & PNG_COLOR_MASK_COLOR)
G
Guy Schalnat 已提交
444
   {
445
      int num_palette;
A
Andreas Dilger 已提交
446 447 448
      png_colorp palette;

      /* This reduces the image to the application supplied palette */
449
      if (/* We have our own palette */)
G
Guy Schalnat 已提交
450
      {
451
         /* An array of colors to which the image should be quantized */
A
Andreas Dilger 已提交
452
         png_color std_color_cube[MAX_SCREEN_COLORS];
G
Guy Schalnat 已提交
453

454
         png_set_quantize(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
455
            MAX_SCREEN_COLORS, NULL, 0);
A
Andreas Dilger 已提交
456 457
      }
      /* This reduces the image to the palette supplied in the file */
458
      else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
A
Andreas Dilger 已提交
459
      {
460
         png_uint_16p histogram = NULL;
A
Andreas Dilger 已提交
461 462 463

         png_get_hIST(png_ptr, info_ptr, &histogram);

464
         png_set_quantize(png_ptr, palette, num_palette,
A
Andreas Dilger 已提交
465
                        max_screen_colors, histogram, 0);
G
Guy Schalnat 已提交
466
      }
G
Guy Schalnat 已提交
467
   }
468
#endif /* PNG_READ_QUANTIZE_SUPPORTED */
G
Guy Schalnat 已提交
469

470
   /* Invert monochrome files to have 0 as white and 1 as black */
471
   png_set_invert_mono(png_ptr);
G
Guy Schalnat 已提交
472

A
Andreas Dilger 已提交
473 474 475 476 477 478
   /* If you want to shift the pixel values from the range [0,255] or
    * [0,65535] to the original [0,7] or [0,31], or whatever range the
    * colors were originally in:
    */
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
   {
479
      png_color_8p sig_bit_p;
A
Andreas Dilger 已提交
480

481 482
      png_get_sBIT(png_ptr, info_ptr, &sig_bit_p);
      png_set_shift(png_ptr, sig_bit_p);
A
Andreas Dilger 已提交
483
   }
G
Guy Schalnat 已提交
484

485
   /* Flip the RGB pixels to BGR (or RGBA to BGRA) */
486 487
   if (color_type & PNG_COLOR_MASK_COLOR)
      png_set_bgr(png_ptr);
G
Guy Schalnat 已提交
488

489
   /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
A
Andreas Dilger 已提交
490
   png_set_swap_alpha(png_ptr);
G
Guy Schalnat 已提交
491

492
   /* Swap bytes of 16 bit files to least significant byte first */
A
Andreas Dilger 已提交
493
   png_set_swap(png_ptr);
G
Guy Schalnat 已提交
494

A
Andreas Dilger 已提交
495 496
   /* Add filler (or alpha) byte (before/after each RGB triplet) */
   png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
G
Guy Schalnat 已提交
497

498
#ifdef PNG_READ_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
499 500
   /* Turn on interlace handling.  REQUIRED if you are not using
    * png_read_image().  To see how to handle interlacing passes,
501
    * see the png_read_row() method below:
A
Andreas Dilger 已提交
502
    */
G
Guy Schalnat 已提交
503
   number_passes = png_set_interlace_handling(png_ptr);
504 505 506 507
#else
   number_passes = 1;
#endif /* PNG_READ_INTERLACING_SUPPORTED */

G
Guy Schalnat 已提交
508

509
   /* Optional call to gamma correct and add the background to the palette
A
Andreas Dilger 已提交
510 511 512
    * and update info structure.  REQUIRED if you are expecting libpng to
    * update the palette for you (ie you selected such a transform above).
    */
G
Guy Schalnat 已提交
513 514
   png_read_update_info(png_ptr, info_ptr);

515
   /* Allocate the memory to hold the image using the fields of info_ptr. */
G
Guy Schalnat 已提交
516

517
   /* The easiest way to read the image: */
G
Guy Schalnat 已提交
518
   png_bytep row_pointers[height];
G
Guy Schalnat 已提交
519

520 521 522 523
   /* Clear the pointer array */
   for (row = 0; row < height; row++)
      row_pointers[row] = NULL;

G
Guy Schalnat 已提交
524
   for (row = 0; row < height; row++)
525 526
      row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
         info_ptr));
G
Guy Schalnat 已提交
527

A
Andreas Dilger 已提交
528
   /* Now it's time to read the image.  One of these methods is REQUIRED */
529
#ifdef entire /* Read the entire image in one go */
G
Guy Schalnat 已提交
530 531
   png_read_image(png_ptr, row_pointers);

532
#else no_entire /* Read the image one or more scanlines at a time */
533
   /* The other way to read images - deal with interlacing: */
G
Guy Schalnat 已提交
534 535 536

   for (pass = 0; pass < number_passes; pass++)
   {
537
#ifdef single /* Read the image a single row at a time */
G
Guy Schalnat 已提交
538 539
      for (y = 0; y < height; y++)
      {
540
         png_read_rows(png_ptr, &row_pointers[y], NULL, 1);
G
Guy Schalnat 已提交
541 542
      }

543
#else no_single /* Read the image several rows at a time */
A
Andreas Dilger 已提交
544 545
      for (y = 0; y < height; y += number_of_rows)
      {
546
#ifdef sparkle /* Read the image using the "sparkle" effect. */
547 548
         png_read_rows(png_ptr, &row_pointers[y], NULL,
            number_of_rows);
549
#else no_sparkle /* Read the image using the "rectangle" effect */
550 551
         png_read_rows(png_ptr, NULL, &row_pointers[y],
            number_of_rows);
552
#endif no_sparkle /* Use only one of these two methods */
A
Andreas Dilger 已提交
553
      }
554

555 556
      /* If you want to display the image after every pass, do so here */
#endif no_single /* Use only one of these two methods */
G
Guy Schalnat 已提交
557
   }
558
#endif no_entire /* Use only one of these two methods */
G
Guy Schalnat 已提交
559

560
   /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
G
Guy Schalnat 已提交
561
   png_read_end(png_ptr, info_ptr);
562 563 564
#endif hilevel

   /* At this point you have read the entire image */
G
Guy Schalnat 已提交
565

566
   /* Clean up after the read, and free any memory allocated - REQUIRED */
567
   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
G
Guy Schalnat 已提交
568

569
   /* Close the file */
G
Guy Schalnat 已提交
570 571
   fclose(fp);

572
   /* That's it */
573
   return (OK);
G
Guy Schalnat 已提交
574 575
}

576
/* Progressively read a file */
G
Guy Schalnat 已提交
577 578

int
G
Guy Schalnat 已提交
579
initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
G
Guy Schalnat 已提交
580
{
G
Guy Schalnat 已提交
581
   /* Create and initialize the png_struct with the desired error handler
A
Andreas Dilger 已提交
582 583 584 585
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also check that
    * the library version is compatible in case we are using dynamically
    * linked libraries.
G
Guy Schalnat 已提交
586 587
    */
   *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
588
       png_voidp user_error_ptr, user_error_fn, user_warning_fn);
G
Guy Schalnat 已提交
589

A
Andreas Dilger 已提交
590
   if (*png_ptr == NULL)
G
Guy Schalnat 已提交
591
   {
G
Guy Schalnat 已提交
592
      *info_ptr = NULL;
593
      return (ERROR);
G
Guy Schalnat 已提交
594 595
   }

G
Guy Schalnat 已提交
596 597
   *info_ptr = png_create_info_struct(png_ptr);

A
Andreas Dilger 已提交
598
   if (*info_ptr == NULL)
G
Guy Schalnat 已提交
599
   {
600
      png_destroy_read_struct(png_ptr, info_ptr, NULL);
601
      return (ERROR);
G
Guy Schalnat 已提交
602 603
   }

604
   if (setjmp(png_jmpbuf((*png_ptr))))
G
Guy Schalnat 已提交
605
   {
606
      png_destroy_read_struct(png_ptr, info_ptr, NULL);
607
      return (ERROR);
G
Guy Schalnat 已提交
608
   }
G
Guy Schalnat 已提交
609

610
   /* This one's new.  You will need to provide all three
A
Andreas Dilger 已提交
611
    * function callbacks, even if you aren't using them all.
612 613 614
    * If you aren't using all functions, you can specify NULL
    * parameters.  Even when all three functions are NULL,
    * you need to call png_set_progressive_read_fn().
A
Andreas Dilger 已提交
615 616 617 618 619 620 621
    * These functions shouldn't be dependent on global or
    * static variables if you are decoding several images
    * simultaneously.  You should store stream specific data
    * in a separate struct, given as the second parameter,
    * and retrieve the pointer from inside the callbacks using
    * the function png_get_progressive_ptr(png_ptr).
    */
G
Guy Schalnat 已提交
622
   png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
G
Guy Schalnat 已提交
623 624
      info_callback, row_callback, end_callback);

625
   return (OK);
G
Guy Schalnat 已提交
626 627 628
}

int
G
Guy Schalnat 已提交
629 630
process_data(png_structp *png_ptr, png_infop *info_ptr,
   png_bytep buffer, png_uint_32 length)
G
Guy Schalnat 已提交
631
{
632
   if (setjmp(png_jmpbuf((*png_ptr))))
G
Guy Schalnat 已提交
633
   {
G
Guy Schalnat 已提交
634
      /* Free the png_ptr and info_ptr memory on error */
635
      png_destroy_read_struct(png_ptr, info_ptr, NULL);
636
      return (ERROR);
G
Guy Schalnat 已提交
637 638
   }

A
Andreas Dilger 已提交
639 640
   /* This one's new also.  Simply give it chunks of data as
    * they arrive from the data stream (in order, of course).
641
    * On segmented machines, don't give it any more than 64K.
A
Andreas Dilger 已提交
642 643 644 645 646 647 648
    * The library seems to run fine with sizes of 4K, although
    * you can give it much less if necessary (I assume you can
    * give it chunks of 1 byte, but I haven't tried with less
    * than 256 bytes yet).  When this function returns, you may
    * want to display any rows that were generated in the row
    * callback, if you aren't already displaying them there.
    */
G
Guy Schalnat 已提交
649
   png_process_data(*png_ptr, *info_ptr, buffer, length);
650
   return (OK);
G
Guy Schalnat 已提交
651 652 653 654
}

info_callback(png_structp png_ptr, png_infop info)
{
655 656 657 658 659 660 661
   /* Do any setup here, including setting any of the transformations
    * mentioned in the Reading PNG files section.  For now, you _must_
    * call either png_start_read_image() or png_read_update_info()
    * after all the transformations are set (even if you don't set
    * any).  You may start getting rows before png_process_data()
    * returns, so this is your last chance to prepare for that.
    */
G
Guy Schalnat 已提交
662 663 664
}

row_callback(png_structp png_ptr, png_bytep new_row,
G
Guy Schalnat 已提交
665
   png_uint_32 row_num, int pass)
G
Guy Schalnat 已提交
666
{
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
   /*
    * This function is called for every row in the image.  If the
    * image is interlaced, and you turned on the interlace handler,
    * this function will be called for every row in every pass.
    *
    * In this function you will receive a pointer to new row data from
    * libpng called new_row that is to replace a corresponding row (of
    * the same data format) in a buffer allocated by your application.
    *
    * The new row data pointer "new_row" may be NULL, indicating there is
    * no new data to be replaced (in cases of interlace loading).
    *
    * If new_row is not NULL then you need to call
    * png_progressive_combine_row() to replace the corresponding row as
    * shown below:
    */

684 685 686 687 688
   /* Get pointer to corresponding row in our
    * PNG read buffer.
    */
   png_bytep old_row = ((png_bytep *)our_data)[row_num];

689
#ifdef PNG_READ_INTERLACING_SUPPORTED
690 691 692 693 694 695
   /* If both rows are allocated then copy the new row
    * data to the corresponding row data.
    */
   if ((old_row != NULL) && (new_row != NULL))
   png_progressive_combine_row(png_ptr, old_row, new_row);

696 697 698 699 700 701 702 703 704 705 706 707
   /*
    * The rows and passes are called in order, so you don't really
    * need the row_num and pass, but I'm supplying them because it
    * may make your life easier.
    *
    * For the non-NULL rows of interlaced images, you must call
    * png_progressive_combine_row() passing in the new row and the
    * old row, as demonstrated above.  You can call this function for
    * NULL rows (it will just return) and for non-interlaced images
    * (it just does the png_memcpy for you) if it will make the code
    * easier.  Thus, you can just do this for all cases:
    */
G
Guy Schalnat 已提交
708 709 710

   png_progressive_combine_row(png_ptr, old_row, new_row);

711 712 713 714 715 716 717
   /* where old_row is what was displayed for previous rows.  Note
    * that the first pass (pass == 0 really) will completely cover
    * the old row, so the rows do not have to be initialized.  After
    * the first pass (and only for interlaced images), you will have
    * to pass the current row as new_row, and the function will combine
    * the old row and the new row.
    */
718
#endif /* PNG_READ_INTERLACING_SUPPORTED */
G
Guy Schalnat 已提交
719 720 721 722
}

end_callback(png_structp png_ptr, png_infop info)
{
723 724 725 726 727 728 729 730 731
   /* This function is called when the whole image has been read,
    * including any chunks after the image (up to and including
    * the IEND).  You will usually have the same info chunk as you
    * had in the header, although some data may have been added
    * to the comments and time fields.
    *
    * Most people won't do much here, perhaps setting a flag that
    * marks the image as finished.
    */
G
Guy Schalnat 已提交
732 733
}

734
/* Write a png file */
735
void write_png(char *file_name /* , ... other image information ... */)
G
Guy Schalnat 已提交
736 737
{
   FILE *fp;
G
Guy Schalnat 已提交
738 739
   png_structp png_ptr;
   png_infop info_ptr;
740
   png_colorp palette;
G
Guy Schalnat 已提交
741

742
   /* Open the file */
G
Guy Schalnat 已提交
743
   fp = fopen(file_name, "wb");
A
Andreas Dilger 已提交
744
   if (fp == NULL)
745
      return (ERROR);
G
Guy Schalnat 已提交
746

G
Guy Schalnat 已提交
747
   /* Create and initialize the png_struct with the desired error handler
A
Andreas Dilger 已提交
748 749 750 751
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also check that
    * the library version is compatible with the one used at compile time,
    * in case we are using dynamically linked libraries.  REQUIRED.
G
Guy Schalnat 已提交
752 753
    */
   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
754
      png_voidp user_error_ptr, user_error_fn, user_warning_fn);
G
Guy Schalnat 已提交
755

A
Andreas Dilger 已提交
756
   if (png_ptr == NULL)
G
Guy Schalnat 已提交
757 758
   {
      fclose(fp);
759
      return (ERROR);
G
Guy Schalnat 已提交
760 761
   }

A
Andreas Dilger 已提交
762
   /* Allocate/initialize the image information data.  REQUIRED */
G
Guy Schalnat 已提交
763
   info_ptr = png_create_info_struct(png_ptr);
A
Andreas Dilger 已提交
764
   if (info_ptr == NULL)
G
Guy Schalnat 已提交
765 766
   {
      fclose(fp);
767
      png_destroy_write_struct(&png_ptr,  NULL);
768
      return (ERROR);
G
Guy Schalnat 已提交
769 770
   }

A
Andreas Dilger 已提交
771
   /* Set error handling.  REQUIRED if you aren't supplying your own
772
    * error handling functions in the png_create_write_struct() call.
A
Andreas Dilger 已提交
773
    */
774
   if (setjmp(png_jmpbuf(png_ptr)))
G
Guy Schalnat 已提交
775
   {
776
      /* If we get here, we had a problem writing the file */
G
Guy Schalnat 已提交
777
      fclose(fp);
778
      png_destroy_write_struct(&png_ptr, &info_ptr);
779
      return (ERROR);
G
Guy Schalnat 已提交
780 781
   }

A
Andreas Dilger 已提交
782
   /* One of the following I/O initialization functions is REQUIRED */
783

784
#ifdef streams /* I/O initialization method 1 */
785
   /* Set up the output control if you are using standard C streams */
G
Guy Schalnat 已提交
786
   png_init_io(png_ptr, fp);
787

788
#else no_streams /* I/O initialization method 2 */
789
   /* If you are using replacement write functions, instead of calling
790 791
    * png_init_io() here you would call
    */
A
Andreas Dilger 已提交
792 793 794
   png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn,
      user_IO_flush_function);
   /* where user_io_ptr is a structure you want available to the callbacks */
795
#endif no_streams /* Only use one initialization method */
A
Andreas Dilger 已提交
796

797 798
#ifdef hilevel
   /* This is the easy way.  Use it if you already have all the
799
    * image info living in the structure.  You could "|" many
800 801
    * PNG_TRANSFORM flags into the png_transforms integer here.
    */
802
   png_write_png(png_ptr, info_ptr, png_transforms, NULL);
803

804 805 806
#else
   /* This is the hard way */

A
Andreas Dilger 已提交
807 808 809 810 811 812 813 814 815 816
   /* Set the image information here.  Width and height are up to 2^31,
    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
    */
   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???,
      PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
G
Guy Schalnat 已提交
817

818
   /* Set the palette if there is one.  REQUIRED for indexed-color images */
819
   palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
820
             * png_sizeof(png_color));
821
   /* ... Set palette colors ... */
822
   png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
823
   /* You must not free palette here, because png_set_PLTE only makes a link to
824 825 826
    * the palette that you malloced.  Wait until you are about to destroy
    * the png structure.
    */
G
Guy Schalnat 已提交
827

828
   /* Optional significant bit (sBIT) chunk */
829
   png_color_8 sig_bit;
830

831
   /* If we are dealing with a grayscale image then */
A
Andreas Dilger 已提交
832
   sig_bit.gray = true_bit_depth;
833

834
   /* Otherwise, if we are dealing with a color image then */
A
Andreas Dilger 已提交
835 836 837
   sig_bit.red = true_red_bit_depth;
   sig_bit.green = true_green_bit_depth;
   sig_bit.blue = true_blue_bit_depth;
838

839
   /* If the image has an alpha channel then */
A
Andreas Dilger 已提交
840
   sig_bit.alpha = true_alpha_bit_depth;
841

842
   png_set_sBIT(png_ptr, info_ptr, &sig_bit);
G
Guy Schalnat 已提交
843

844

A
Andreas Dilger 已提交
845
   /* Optional gamma chunk is strongly suggested if you have any guess
846 847
    * as to the correct gamma of the image.
    */
A
Andreas Dilger 已提交
848 849 850 851 852 853
   png_set_gAMA(png_ptr, info_ptr, gamma);

   /* Optionally write comments into the image */
   text_ptr[0].key = "Title";
   text_ptr[0].text = "Mona Lisa";
   text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
854 855 856
   text_ptr[0].itxt_length = 0;
   text_ptr[0].lang = NULL;
   text_ptr[0].lang_key = NULL;
A
Andreas Dilger 已提交
857 858 859
   text_ptr[1].key = "Author";
   text_ptr[1].text = "Leonardo DaVinci";
   text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
860 861 862
   text_ptr[1].itxt_length = 0;
   text_ptr[1].lang = NULL;
   text_ptr[1].lang_key = NULL;
A
Andreas Dilger 已提交
863 864 865
   text_ptr[2].key = "Description";
   text_ptr[2].text = "<long text>";
   text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
866
   text_ptr[2].itxt_length = 0;
867
   text_ptr[2].lang = NULL;
868
   text_ptr[2].lang_key = NULL;
869
   png_set_text(png_ptr, info_ptr, text_ptr, 3);
A
Andreas Dilger 已提交
870

871
   /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */
872

873
   /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored
874
    * on read and, if your application chooses to write them, they must
875 876
    * be written in accordance with the sRGB profile
    */
A
Andreas Dilger 已提交
877 878

   /* Write the file header information.  REQUIRED */
G
Guy Schalnat 已提交
879 880
   png_write_info(png_ptr, info_ptr);

881 882 883 884 885 886
   /* If you want, you can write the info in two steps, in case you need to
    * write your private chunk ahead of PLTE:
    *
    *   png_write_info_before_PLTE(write_ptr, write_info_ptr);
    *   write_my_chunk();
    *   png_write_info(png_ptr, info_ptr);
887
    *
888
    * However, given the level of known- and unknown-chunk support in 1.2.0
889
    * and up, this should no longer be necessary.
890 891
    */

A
Andreas Dilger 已提交
892 893 894 895 896 897
   /* Once we write out the header, the compression type on the text
    * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
    * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
    * at the end.
    */

898
   /* Set up the transformations you want.  Note that these are
899 900
    * all optional.  Only call them if you want them.
    */
G
Guy Schalnat 已提交
901

902
   /* Invert monochrome pixels */
903
   png_set_invert_mono(png_ptr);
G
Guy Schalnat 已提交
904

A
Andreas Dilger 已提交
905
   /* Shift the pixels up to a legal bit depth and fill in
906 907
    * as appropriate to correctly scale the image.
    */
A
Andreas Dilger 已提交
908
   png_set_shift(png_ptr, &sig_bit);
G
Guy Schalnat 已提交
909

910
   /* Pack pixels into bytes */
G
Guy Schalnat 已提交
911 912
   png_set_packing(png_ptr);

913
   /* Swap location of alpha bytes from ARGB to RGBA */
A
Andreas Dilger 已提交
914 915 916
   png_set_swap_alpha(png_ptr);

   /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
917 918
    * RGB (4 channels -> 3 channels). The second parameter is not used.
    */
A
Andreas Dilger 已提交
919 920
   png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

921
   /* Flip BGR pixels to RGB */
G
Guy Schalnat 已提交
922 923
   png_set_bgr(png_ptr);

924
   /* Swap bytes of 16-bit files to most significant byte first */
G
Guy Schalnat 已提交
925 926
   png_set_swap(png_ptr);

927
   /* Swap bits of 1, 2, 4 bit packed pixel formats */
A
Andreas Dilger 已提交
928
   png_set_packswap(png_ptr);
G
Guy Schalnat 已提交
929

930
   /* Turn on interlace handling if you are not using png_write_image() */
G
Guy Schalnat 已提交
931 932
   if (interlacing)
      number_passes = png_set_interlace_handling(png_ptr);
933

G
Guy Schalnat 已提交
934 935 936
   else
      number_passes = 1;

A
Andreas Dilger 已提交
937 938 939 940
   /* The easiest way to write the image (you may have a different memory
    * layout, however, so choose what fits your needs best).  You need to
    * use the first method if you aren't handling interlacing yourself.
    */
941
   png_uint_32 k, height, width;
942
   png_byte image[height][width*bytes_per_pixel];
943
   png_bytep row_pointers[height];
944

945
   if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
946 947
     png_error (png_ptr, "Image is too tall to process in memory");

948
   for (k = 0; k < height; k++)
949
     row_pointers[k] = image + k*width*bytes_per_pixel;
G
Guy Schalnat 已提交
950

A
Andreas Dilger 已提交
951
   /* One of the following output methods is REQUIRED */
952 953

#ifdef entire /* Write out the entire image data in one call */
G
Guy Schalnat 已提交
954 955
   png_write_image(png_ptr, row_pointers);

956
   /* The other way to write the image - deal with interlacing */
G
Guy Schalnat 已提交
957

958 959
#else no_entire /* Write out the image data by one or more scanlines */

A
Andreas Dilger 已提交
960 961 962
   /* The number of passes is either 1 for non-interlaced images,
    * or 7 for interlaced images.
    */
G
Guy Schalnat 已提交
963 964 965
   for (pass = 0; pass < number_passes; pass++)
   {
      /* Write a few rows at a time. */
966
      png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows);
G
Guy Schalnat 已提交
967 968 969

      /* If you are only writing one row at a time, this works */
      for (y = 0; y < height; y++)
970
         png_write_rows(png_ptr, &row_pointers[y], 1);
G
Guy Schalnat 已提交
971
   }
972
#endif no_entire /* Use only one output method */
G
Guy Schalnat 已提交
973

A
Andreas Dilger 已提交
974
   /* You can write optional chunks like tEXt, zTXt, and tIME at the end
975
    * as well.  Shouldn't be necessary in 1.2.0 and up as all the public
976 977
    * chunks are supported and you can use png_set_unknown_chunks() to
    * register unknown chunks into the info structure to be written out.
G
Guy Schalnat 已提交
978 979
    */

A
Andreas Dilger 已提交
980
   /* It is REQUIRED to call this to finish writing the rest of the file */
G
Guy Schalnat 已提交
981
   png_write_end(png_ptr, info_ptr);
982
#endif hilevel
G
Guy Schalnat 已提交
983

984
   /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
985 986 987 988 989
    * as recommended in versions 1.0.5m and earlier of this example; if
    * libpng mallocs info_ptr->palette, libpng will free it).  If you
    * allocated it with malloc() instead of png_malloc(), use free() instead
    * of png_free().
    */
990
   png_free(png_ptr, palette);
991
   palette = NULL;
992 993

   /* Similarly, if you png_malloced any data that you passed in with
994 995 996
    * png_set_something(), such as a hist or trans array, free it here,
    * when you can be sure that libpng is through with it.
    */
997
   png_free(png_ptr, trans);
998
   trans = NULL;
999 1000 1001 1002 1003
   /* Whenever you use png_free() it is a good idea to set the pointer to
    * NULL in case your application inadvertently tries to png_free() it
    * again.  When png_free() sees a NULL it returns without action, thus
    * avoiding the double-free security problem.
    */
G
Guy Schalnat 已提交
1004

1005
   /* Clean up after the write, and free any memory allocated */
1006
   png_destroy_write_struct(&png_ptr, &info_ptr);
G
Guy Schalnat 已提交
1007

1008
   /* Close the file */
G
Guy Schalnat 已提交
1009 1010
   fclose(fp);

1011
   /* That's it */
1012
   return (OK);
G
Guy Schalnat 已提交
1013 1014
}

1015
#endif /* if 0 */