example.c 29.0 KB
Newer Older
1

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

G
Guy Schalnat 已提交
4 5
/* example.c - an example of using libpng */

A
Andreas Dilger 已提交
6
/* This is an example of how to use libpng to read and write PNG files.
7 8
 * The file libpng.txt is much more verbose then this.  If you have not
 * read it, do so first.  This was designed to be a starting point of an
9 10
 * implementation.  This is not officially part of libpng, is hereby placed
 * in the public domain, and therefore does not require a copyright notice.
11 12 13 14
 *
 * 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
15 16
 * working PNG reader/writer, see pngtest.c, included in this distribution;
 * see also the programs in the contrib directory.
17
 */
G
Guy Schalnat 已提交
18

19
#include "png.h"
G
Guy Schalnat 已提交
20

21 22 23 24 25 26 27 28 29 30
 /* 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
#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
#endif

31 32 33 34 35
/* 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.
36 37 38 39 40 41 42 43 44 45 46 47
 *
 * 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
48
 * to pass the bytes to png_sig_cmp() or even skip that if you know
49 50
 * you have a PNG file, and call png_set_sig_bytes().
 */
A
Andreas Dilger 已提交
51 52
#define PNG_BYTES_TO_CHECK 4
int check_if_png(char *file_name, FILE **fp)
G
Guy Schalnat 已提交
53
{
A
Andreas Dilger 已提交
54
   char buf[PNG_BYTES_TO_CHECK];
G
Guy Schalnat 已提交
55

A
Andreas Dilger 已提交
56
   /* Open the prospective PNG file. */
57
   if ((*fp = fopen(file_name, "rb")) == NULL)
G
Guy Schalnat 已提交
58 59
      return 0;

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

64 65 66 67
   /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
      Return nonzero (true) if they match */

   return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
G
Guy Schalnat 已提交
68 69
}

A
Andreas Dilger 已提交
70
/* Read a PNG file.  You may want to return an error code if the read
71 72 73 74 75
 * 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).
 */
76
#ifdef open_file /* prototype 1 */
A
Andreas Dilger 已提交
77
void read_png(char *file_name)  /* We need to open the file */
G
Guy Schalnat 已提交
78
{
G
Guy Schalnat 已提交
79
   png_structp png_ptr;
G
Guy Schalnat 已提交
80
   png_infop info_ptr;
A
Andreas Dilger 已提交
81 82 83
   unsigned int sig_read = 0;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
A
Andreas Dilger 已提交
84
   FILE *fp;
G
Guy Schalnat 已提交
85

A
Andreas Dilger 已提交
86
   if ((fp = fopen(file_name, "rb")) == NULL)
87
      return (ERROR);
88
#else no_open_file /* prototype 2 */
A
Andreas Dilger 已提交
89 90 91 92
void read_png(FILE *fp, unsigned int sig_read)  /* file is already open */
{
   png_structp png_ptr;
   png_infop info_ptr;
A
Andreas Dilger 已提交
93 94
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
95
#endif no_open_file /* only use one prototype! */
G
Guy Schalnat 已提交
96

G
Guy Schalnat 已提交
97
   /* Create and initialize the png_struct with the desired error handler
A
Andreas Dilger 已提交
98 99 100 101 102
    * 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 已提交
103
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
104
      png_voidp user_error_ptr, user_error_fn, user_warning_fn);
G
Guy Schalnat 已提交
105

A
Andreas Dilger 已提交
106
   if (png_ptr == NULL)
G
Guy Schalnat 已提交
107 108
   {
      fclose(fp);
109
      return (ERROR);
G
Guy Schalnat 已提交
110 111
   }

A
Andreas Dilger 已提交
112
   /* Allocate/initialize the memory for image information.  REQUIRED. */
113
   info_ptr = png_create_info_struct(png_ptr);
A
Andreas Dilger 已提交
114
   if (info_ptr == NULL)
G
Guy Schalnat 已提交
115 116
   {
      fclose(fp);
117
      png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
118
      return (ERROR);
G
Guy Schalnat 已提交
119 120
   }

A
Andreas Dilger 已提交
121 122 123 124
   /* 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.
    */
125 126

   if (setjmp(png_jmpbuf(png_ptr)))
G
Guy Schalnat 已提交
127
   {
G
Guy Schalnat 已提交
128
      /* Free all of the memory associated with the png_ptr and info_ptr */
129
      png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
G
Guy Schalnat 已提交
130 131
      fclose(fp);
      /* If we get here, we had a problem reading the file */
132
      return (ERROR);
G
Guy Schalnat 已提交
133 134
   }

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

140
#else no_streams /* PNG file I/O method 2 */
A
Andreas Dilger 已提交
141
   /* If you are using replacement read functions, instead of calling
142 143
    * png_init_io() here you would call:
    */
G
Guy Schalnat 已提交
144 145
   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 */
146
#endif no_streams /* Use only one I/O method! */
G
Guy Schalnat 已提交
147

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

151 152 153 154 155 156 157 158 159
#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
    * dithering, filling, setting background, and doing gamma
    * adjustment), then you can read the entire image (including
    * pixels) into the info structure with this call:
    */
160
   png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
161 162 163
#else
   /* OK, you're doing it the hard way, with the lower-level functions */

A
Andreas Dilger 已提交
164 165 166
   /* 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 已提交
167
   png_read_info(png_ptr, info_ptr);
G
Guy Schalnat 已提交
168

A
Andreas Dilger 已提交
169
   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
170
       &interlace_type, int_p_NULL, int_p_NULL);
A
Andreas Dilger 已提交
171

172 173 174 175 176
/* 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 已提交
177 178 179 180

   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
   png_set_strip_16(png_ptr);

181
   /* Strip alpha bytes from the input data without combining with the
182 183
    * background (not recommended).
    */
A
Andreas Dilger 已提交
184 185
   png_set_strip_alpha(png_ptr);

186
   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
A
Andreas Dilger 已提交
187 188 189 190
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   png_set_packing(png_ptr);

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

195
   /* Expand paletted colors into true RGB triplets */
A
Andreas Dilger 已提交
196
   if (color_type == PNG_COLOR_TYPE_PALETTE)
197
      png_set_palette_rgb(png_ptr);
G
Guy Schalnat 已提交
198

199
   /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
A
Andreas Dilger 已提交
200
   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
201
      png_set_gray_1_2_4_to_8(png_ptr);
G
Guy Schalnat 已提交
202

203 204 205
   /* Expand paletted or RGB images with transparency to full alpha channels
    * so the data will be available as RGBA quartets.
    */
A
Andreas Dilger 已提交
206
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
207
      png_set_tRNS_to_alpha(png_ptr);
G
Guy Schalnat 已提交
208

A
Andreas Dilger 已提交
209 210 211 212 213 214
   /* 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 已提交
215

216
   png_color_16 my_background, *image_background;
G
Guy Schalnat 已提交
217

218 219
   if (png_get_bKGD(png_ptr, info_ptr, &image_background))
      png_set_background(png_ptr, image_background,
G
Guy Schalnat 已提交
220
                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
G
Guy Schalnat 已提交
221 222
   else
      png_set_background(png_ptr, &my_background,
G
Guy Schalnat 已提交
223
                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
G
Guy Schalnat 已提交
224

A
Andreas Dilger 已提交
225
   /* Some suggestions as to how to get a screen gamma value */
226

227 228
   /* Note that screen gamma is the display_exponent, which includes
    * the CRT_exponent and any correction for viewing conditions */
A
Andreas Dilger 已提交
229 230 231 232 233
   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 */
234
   else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
A
Andreas Dilger 已提交
235 236 237 238
   {
      screen_gamma = atof(gamma_str);
   }
   /* If we don't have another value */
G
Guy Schalnat 已提交
239
   else
A
Andreas Dilger 已提交
240
   {
241
      screen_gamma = 2.2;  /* A good guess for a PC monitors in a dimly
242
                              lit room */
A
Andreas Dilger 已提交
243 244
      screen_gamma = 1.7 or 1.0;  /* A good guess for Mac systems */
   }
G
Guy Schalnat 已提交
245

246
   /* Tell libpng to handle the gamma conversion for you.  The final call
A
Andreas Dilger 已提交
247 248 249 250
    * 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.
    */
251 252 253

   int intent;

254
   if (png_get_sRGB(png_ptr, info_ptr, &intent))
255
      png_set_gamma(png_ptr, screen_gamma, 0.45455);
256 257 258
   else
   {
      double image_gamma;
259
      if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
260 261
         png_set_gamma(png_ptr, screen_gamma, image_gamma);
      else
262 263
         png_set_gamma(png_ptr, screen_gamma, 0.45455);
   }
G
Guy Schalnat 已提交
264

A
Andreas Dilger 已提交
265
   /* Dither RGB files down to 8 bit palette or reduce palettes
266 267
    * to the number of colors available on your screen.
    */
A
Andreas Dilger 已提交
268
   if (color_type & PNG_COLOR_MASK_COLOR)
G
Guy Schalnat 已提交
269
   {
270
      int num_palette;
A
Andreas Dilger 已提交
271 272 273
      png_colorp palette;

      /* This reduces the image to the application supplied palette */
274
      if (/* we have our own palette */)
G
Guy Schalnat 已提交
275
      {
A
Andreas Dilger 已提交
276 277
         /* An array of colors to which the image should be dithered */
         png_color std_color_cube[MAX_SCREEN_COLORS];
G
Guy Schalnat 已提交
278 279

         png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
280
            MAX_SCREEN_COLORS, png_uint_16p_NULL, 0);
A
Andreas Dilger 已提交
281 282
      }
      /* This reduces the image to the palette supplied in the file */
283
      else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
A
Andreas Dilger 已提交
284
      {
285
         png_uint_16p histogram = NULL;
A
Andreas Dilger 已提交
286 287 288 289 290

         png_get_hIST(png_ptr, info_ptr, &histogram);

         png_set_dither(png_ptr, palette, num_palette,
                        max_screen_colors, histogram, 0);
G
Guy Schalnat 已提交
291
      }
G
Guy Schalnat 已提交
292
   }
G
Guy Schalnat 已提交
293

294
   /* invert monochrome files to have 0 as white and 1 as black */
295
   png_set_invert_mono(png_ptr);
G
Guy Schalnat 已提交
296

A
Andreas Dilger 已提交
297 298 299 300 301 302
   /* 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))
   {
303
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
304 305 306 307

      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
      png_set_shift(png_ptr, sig_bit);
   }
G
Guy Schalnat 已提交
308

A
Andreas Dilger 已提交
309
   /* flip the RGB pixels to BGR (or RGBA to BGRA) */
310 311
   if (color_type & PNG_COLOR_MASK_COLOR)
      png_set_bgr(png_ptr);
G
Guy Schalnat 已提交
312

A
Andreas Dilger 已提交
313 314
   /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
   png_set_swap_alpha(png_ptr);
G
Guy Schalnat 已提交
315

A
Andreas Dilger 已提交
316 317
   /* swap bytes of 16 bit files to least significant byte first */
   png_set_swap(png_ptr);
G
Guy Schalnat 已提交
318

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

A
Andreas Dilger 已提交
322 323
   /* Turn on interlace handling.  REQUIRED if you are not using
    * png_read_image().  To see how to handle interlacing passes,
324
    * see the png_read_row() method below:
A
Andreas Dilger 已提交
325
    */
G
Guy Schalnat 已提交
326
   number_passes = png_set_interlace_handling(png_ptr);
G
Guy Schalnat 已提交
327

328
   /* Optional call to gamma correct and add the background to the palette
A
Andreas Dilger 已提交
329 330 331
    * 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 已提交
332 333
   png_read_update_info(png_ptr, info_ptr);

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

336
   /* The easiest way to read the image: */
G
Guy Schalnat 已提交
337
   png_bytep row_pointers[height];
G
Guy Schalnat 已提交
338 339 340

   for (row = 0; row < height; row++)
   {
341 342
      row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
         info_ptr));
G
Guy Schalnat 已提交
343 344
   }

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

349
#else no_entire /* Read the image one or more scanlines at a time */
350
   /* The other way to read images - deal with interlacing: */
G
Guy Schalnat 已提交
351 352 353

   for (pass = 0; pass < number_passes; pass++)
   {
354
#ifdef single /* Read the image a single row at a time */
G
Guy Schalnat 已提交
355 356
      for (y = 0; y < height; y++)
      {
357
         png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1);
G
Guy Schalnat 已提交
358 359
      }

360
#else no_single /* Read the image several rows at a time */
A
Andreas Dilger 已提交
361 362
      for (y = 0; y < height; y += number_of_rows)
      {
363
#ifdef sparkle /* Read the image using the "sparkle" effect. */
364
         png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL,
365
            number_of_rows);
366
#else no_sparkle /* Read the image using the "rectangle" effect */
367
         png_read_rows(png_ptr, png_bytepp_NULL, &row_pointers[y],
368
            number_of_rows);
369
#endif no_sparkle /* use only one of these two methods */
A
Andreas Dilger 已提交
370
      }
371

G
Guy Schalnat 已提交
372 373
      /* if you want to display the image after every pass, do
         so here */
374
#endif no_single /* use only one of these two methods */
G
Guy Schalnat 已提交
375
   }
376
#endif no_entire /* use only one of these two methods */
G
Guy Schalnat 已提交
377

A
Andreas Dilger 已提交
378
   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
G
Guy Schalnat 已提交
379
   png_read_end(png_ptr, info_ptr);
380 381 382
#endif hilevel

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

A
Andreas Dilger 已提交
384
   /* clean up after the read, and free any memory allocated - REQUIRED */
385
   png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
G
Guy Schalnat 已提交
386 387 388 389 390

   /* close the file */
   fclose(fp);

   /* that's it */
391
   return (OK);
G
Guy Schalnat 已提交
392 393
}

G
Guy Schalnat 已提交
394 395 396
/* progressively read a file */

int
G
Guy Schalnat 已提交
397
initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
G
Guy Schalnat 已提交
398
{
G
Guy Schalnat 已提交
399
   /* Create and initialize the png_struct with the desired error handler
A
Andreas Dilger 已提交
400 401 402 403
    * 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 已提交
404 405
    */
   *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
406
       png_voidp user_error_ptr, user_error_fn, user_warning_fn);
G
Guy Schalnat 已提交
407

A
Andreas Dilger 已提交
408
   if (*png_ptr == NULL)
G
Guy Schalnat 已提交
409
   {
G
Guy Schalnat 已提交
410
      *info_ptr = NULL;
411
      return (ERROR);
G
Guy Schalnat 已提交
412 413
   }

G
Guy Schalnat 已提交
414 415
   *info_ptr = png_create_info_struct(png_ptr);

A
Andreas Dilger 已提交
416
   if (*info_ptr == NULL)
G
Guy Schalnat 已提交
417
   {
418
      png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL);
419
      return (ERROR);
G
Guy Schalnat 已提交
420 421
   }

422
   if (setjmp(png_jmpbuf((*png_ptr))))
G
Guy Schalnat 已提交
423
   {
424
      png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL);
425
      return (ERROR);
G
Guy Schalnat 已提交
426
   }
G
Guy Schalnat 已提交
427

428
   /* This one's new.  You will need to provide all three
A
Andreas Dilger 已提交
429
    * function callbacks, even if you aren't using them all.
430 431 432
    * 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 已提交
433 434 435 436 437 438 439
    * 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 已提交
440
   png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
G
Guy Schalnat 已提交
441 442
      info_callback, row_callback, end_callback);

443
   return (OK);
G
Guy Schalnat 已提交
444 445 446
}

int
G
Guy Schalnat 已提交
447 448
process_data(png_structp *png_ptr, png_infop *info_ptr,
   png_bytep buffer, png_uint_32 length)
G
Guy Schalnat 已提交
449
{
450
   if (setjmp(png_jmpbuf((*png_ptr))))
G
Guy Schalnat 已提交
451
   {
G
Guy Schalnat 已提交
452
      /* Free the png_ptr and info_ptr memory on error */
453
      png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL);
454
      return (ERROR);
G
Guy Schalnat 已提交
455 456
   }

A
Andreas Dilger 已提交
457 458 459 460 461 462 463 464 465 466
   /* This one's new also.  Simply give it chunks of data as
    * they arrive from the data stream (in order, of course).
    * On Segmented machines, don't give it any more than 64K.
    * 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 已提交
467
   png_process_data(*png_ptr, *info_ptr, buffer, length);
468
   return (OK);
G
Guy Schalnat 已提交
469 470 471 472
}

info_callback(png_structp png_ptr, png_infop info)
{
G
Guy Schalnat 已提交
473
/* do any setup here, including setting any of the transformations
A
Andreas Dilger 已提交
474 475 476 477 478 479
 * 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 已提交
480 481 482
}

row_callback(png_structp png_ptr, png_bytep new_row,
G
Guy Schalnat 已提交
483
   png_uint_32 row_num, int pass)
G
Guy Schalnat 已提交
484
{
485 486 487
/*
 * This function is called for every row in the image.  If the
 * image is interlaced, and you turned on the interlace handler,
A
Andreas Dilger 已提交
488
 * this function will be called for every row in every pass.
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
 *
 * 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:
 */
   /* Check if row_num is in bounds. */
   if((row_num >= 0) && (row_num < height))
   {
     /* Get pointer to corresponding row in our
      * PNG read buffer.
      */
     png_bytep old_row = ((png_bytep *)our_data)[row_num];

     /* 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);
   }
/*
A
Andreas Dilger 已提交
516 517 518 519 520
 * 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
521 522 523 524 525
 * 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:
A
Andreas Dilger 已提交
526
 */
G
Guy Schalnat 已提交
527 528 529 530

   png_progressive_combine_row(png_ptr, old_row, new_row);

/* where old_row is what was displayed for previous rows.  Note
A
Andreas Dilger 已提交
531 532 533
 * 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
534 535
 * to pass the current row as new_row, and the function will combine
 * the old row and the new row.
A
Andreas Dilger 已提交
536
 */
G
Guy Schalnat 已提交
537 538 539 540
}

end_callback(png_structp png_ptr, png_infop info)
{
G
Guy Schalnat 已提交
541
/* this function is called when the whole image has been read,
A
Andreas Dilger 已提交
542 543 544 545 546 547 548 549
 * 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 已提交
550 551
}

G
Guy Schalnat 已提交
552
/* write a png file */
553
void write_png(char *file_name /* , ... other image information ... */)
G
Guy Schalnat 已提交
554 555
{
   FILE *fp;
G
Guy Schalnat 已提交
556 557
   png_structp png_ptr;
   png_infop info_ptr;
558
   png_colorp palette;
G
Guy Schalnat 已提交
559 560 561

   /* open the file */
   fp = fopen(file_name, "wb");
A
Andreas Dilger 已提交
562
   if (fp == NULL)
563
      return (ERROR);
G
Guy Schalnat 已提交
564

G
Guy Schalnat 已提交
565
   /* Create and initialize the png_struct with the desired error handler
A
Andreas Dilger 已提交
566 567 568 569
    * 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 已提交
570 571
    */
   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
572
      png_voidp user_error_ptr, user_error_fn, user_warning_fn);
G
Guy Schalnat 已提交
573

A
Andreas Dilger 已提交
574
   if (png_ptr == NULL)
G
Guy Schalnat 已提交
575 576
   {
      fclose(fp);
577
      return (ERROR);
G
Guy Schalnat 已提交
578 579
   }

A
Andreas Dilger 已提交
580
   /* Allocate/initialize the image information data.  REQUIRED */
G
Guy Schalnat 已提交
581
   info_ptr = png_create_info_struct(png_ptr);
A
Andreas Dilger 已提交
582
   if (info_ptr == NULL)
G
Guy Schalnat 已提交
583 584
   {
      fclose(fp);
585
      png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
586
      return (ERROR);
G
Guy Schalnat 已提交
587 588
   }

A
Andreas Dilger 已提交
589
   /* Set error handling.  REQUIRED if you aren't supplying your own
590
    * error handling functions in the png_create_write_struct() call.
A
Andreas Dilger 已提交
591
    */
592
   if (setjmp(png_jmpbuf(png_ptr)))
G
Guy Schalnat 已提交
593 594
   {
      /* If we get here, we had a problem reading the file */
G
Guy Schalnat 已提交
595
      fclose(fp);
596
      png_destroy_write_struct(&png_ptr, &info_ptr);
597
      return (ERROR);
G
Guy Schalnat 已提交
598 599
   }

A
Andreas Dilger 已提交
600
   /* One of the following I/O initialization functions is REQUIRED */
601
#ifdef streams /* I/O initialization method 1 */
G
Guy Schalnat 已提交
602
   /* set up the output control if you are using standard C streams */
G
Guy Schalnat 已提交
603
   png_init_io(png_ptr, fp);
604
#else no_streams /* I/O initialization method 2 */
A
Andreas Dilger 已提交
605 606 607 608 609
   /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call */
   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 */
610
#endif no_streams /* only use one initialization method */
A
Andreas Dilger 已提交
611

612 613 614 615 616
#ifdef hilevel
   /* This is the easy way.  Use it if you already have all the
    * image info living info in the structure.  You could "|" many
    * PNG_TRANSFORM flags into the png_transforms integer here.
    */
617
   png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
618 619 620
#else
   /* This is the hard way */

A
Andreas Dilger 已提交
621 622 623 624 625 626 627 628 629 630
   /* 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 已提交
631

A
Andreas Dilger 已提交
632
   /* set the palette if there is one.  REQUIRED for indexed-color images */
633 634
   palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
             * sizeof (png_color));
635
   /* ... set palette colors ... */
636
   png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
637 638 639
   /* You must not free palette here, because png_set_PLTE only makes a link to
      the palette that you malloced.  Wait until you are about to destroy
      the png structure. */
G
Guy Schalnat 已提交
640 641

   /* optional significant bit chunk */
G
Guy Schalnat 已提交
642
   /* if we are dealing with a grayscale image then */
A
Andreas Dilger 已提交
643
   sig_bit.gray = true_bit_depth;
G
Guy Schalnat 已提交
644
   /* otherwise, if we are dealing with a color image then */
A
Andreas Dilger 已提交
645 646 647
   sig_bit.red = true_red_bit_depth;
   sig_bit.green = true_green_bit_depth;
   sig_bit.blue = true_blue_bit_depth;
G
Guy Schalnat 已提交
648
   /* if the image has an alpha channel then */
A
Andreas Dilger 已提交
649 650
   sig_bit.alpha = true_alpha_bit_depth;
   png_set_sBIT(png_ptr, info_ptr, sig_bit);
G
Guy Schalnat 已提交
651

652

A
Andreas Dilger 已提交
653
   /* Optional gamma chunk is strongly suggested if you have any guess
654 655
    * as to the correct gamma of the image.
    */
A
Andreas Dilger 已提交
656 657 658 659 660 661 662 663 664 665 666 667
   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;
   text_ptr[1].key = "Author";
   text_ptr[1].text = "Leonardo DaVinci";
   text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
   text_ptr[2].key = "Description";
   text_ptr[2].text = "<long text>";
   text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
668 669 670 671 672
#ifdef PNG_iTXt_SUPPORTED
   text_ptr[0].lang = NULL;
   text_ptr[1].lang = NULL;
   text_ptr[2].lang = NULL;
#endif
673
   png_set_text(png_ptr, info_ptr, text_ptr, 3);
A
Andreas Dilger 已提交
674 675

   /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
676
   /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
677
    * on read and must be written in accordance with the sRGB profile */
A
Andreas Dilger 已提交
678 679

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

682 683 684 685 686 687
   /* 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);
688 689 690
    *
    * However, given the level of known- and unknown-chunk support in 1.1.0
    * and up, this should no longer be necessary.
691 692
    */

A
Andreas Dilger 已提交
693 694 695 696 697 698
   /* 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.
    */

G
Guy Schalnat 已提交
699
   /* set up the transformations you want.  Note that these are
700 701
    * all optional.  Only call them if you want them.
    */
G
Guy Schalnat 已提交
702

703
   /* invert monochrome pixels */
704
   png_set_invert_mono(png_ptr);
G
Guy Schalnat 已提交
705

A
Andreas Dilger 已提交
706
   /* Shift the pixels up to a legal bit depth and fill in
707 708
    * as appropriate to correctly scale the image.
    */
A
Andreas Dilger 已提交
709
   png_set_shift(png_ptr, &sig_bit);
G
Guy Schalnat 已提交
710 711 712 713

   /* pack pixels into bytes */
   png_set_packing(png_ptr);

A
Andreas Dilger 已提交
714 715 716 717
   /* swap location of alpha bytes from ARGB to RGBA */
   png_set_swap_alpha(png_ptr);

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

   /* flip BGR pixels to RGB */
G
Guy Schalnat 已提交
723 724
   png_set_bgr(png_ptr);

A
Andreas Dilger 已提交
725
   /* swap bytes of 16-bit files to most significant byte first */
G
Guy Schalnat 已提交
726 727
   png_set_swap(png_ptr);

A
Andreas Dilger 已提交
728 729
   /* swap bits of 1, 2, 4 bit packed pixel formats */
   png_set_packswap(png_ptr);
G
Guy Schalnat 已提交
730

G
Guy Schalnat 已提交
731
   /* turn on interlace handling if you are not using png_write_image() */
G
Guy Schalnat 已提交
732 733 734 735 736
   if (interlacing)
      number_passes = png_set_interlace_handling(png_ptr);
   else
      number_passes = 1;

A
Andreas Dilger 已提交
737 738 739 740
   /* 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.
    */
741
   png_uint_32 k, height, width;
742
   png_byte image[height][width*bytes_per_pixel];
743 744
   png_bytep row_pointers[height];
   for (k = 0; k < height; k++)
745
     row_pointers[k] = image + k*width*bytes_per_pixel;
G
Guy Schalnat 已提交
746

A
Andreas Dilger 已提交
747
   /* One of the following output methods is REQUIRED */
748
#ifdef entire /* write out the entire image data in one call */
G
Guy Schalnat 已提交
749 750 751 752
   png_write_image(png_ptr, row_pointers);

   /* the other way to write the image - deal with interlacing */

753
#else no_entire /* write out the image data by one or more scanlines */
A
Andreas Dilger 已提交
754 755 756
   /* The number of passes is either 1 for non-interlaced images,
    * or 7 for interlaced images.
    */
G
Guy Schalnat 已提交
757 758 759
   for (pass = 0; pass < number_passes; pass++)
   {
      /* Write a few rows at a time. */
760
      png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows);
G
Guy Schalnat 已提交
761 762 763 764

      /* If you are only writing one row at a time, this works */
      for (y = 0; y < height; y++)
      {
765
         png_write_rows(png_ptr, &row_pointers[y], 1);
G
Guy Schalnat 已提交
766 767
      }
   }
768
#endif no_entire /* use only one output method */
G
Guy Schalnat 已提交
769

A
Andreas Dilger 已提交
770
   /* You can write optional chunks like tEXt, zTXt, and tIME at the end
771 772 773
    * as well.  Shouldn't be necessary in 1.1.0 and up as all the public
    * 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 已提交
774 775
    */

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

780 781 782 783 784 785
   /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
      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(). */
   png_free(png_ptr, palette);
786
   palette=NULL;
787 788 789 790 791

   /* Similarly, if you png_malloced any data that you passed in with
      png_set_something(), such as a hist or trans array, free it here,
      when you can be sure that libpng is through with it. */
   png_free(png_ptr, trans);
792
   trans=NULL;
G
Guy Schalnat 已提交
793

G
Guy Schalnat 已提交
794
   /* clean up after the write, and free any memory allocated */
795
   png_destroy_write_struct(&png_ptr, &info_ptr);
G
Guy Schalnat 已提交
796 797 798 799 800

   /* close the file */
   fclose(fp);

   /* that's it */
801
   return (OK);
G
Guy Schalnat 已提交
802 803
}

804
#endif /* if 0 */