source: trunk/third/libpng/example.c @ 18166

Revision 18166, 29.0 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18165, which included commits to RCS files with non-trunk default branches.
Line 
1
2#if 0 /* in case someone actually tries to compile this */
3
4/* example.c - an example of using libpng */
5
6/* This is an example of how to use libpng to read and write PNG files.
7 * The file libpng.txt is much more verbose then this.  If you have not
8 * read it, do so first.  This was designed to be a starting point of an
9 * implementation.  This is not officially part of libpng, is hereby placed
10 * in the public domain, and therefore does not require a copyright notice.
11 *
12 * This file does not currently compile, because it is missing certain
13 * parts, like allocating memory to hold an image.  You will have to
14 * supply these parts to get it to compile.  For an example of a minimal
15 * working PNG reader/writer, see pngtest.c, included in this distribution;
16 * see also the programs in the contrib directory.
17 */
18
19#include "png.h"
20
21 /* The png_jmpbuf() macro, used in error handling, became available in
22  * libpng version 1.0.6.  If you want to be able to run your code with older
23  * versions of libpng, you must define the macro yourself (but only if it
24  * is not already defined by libpng!).
25  */
26
27#ifndef png_jmpbuf
28#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
29#endif
30
31/* Check to see if a file is a PNG file using png_sig_cmp().  png_sig_cmp()
32 * returns zero if the image is a PNG and nonzero if it isn't a PNG.
33 *
34 * The function check_if_png() shown here, but not used, returns nonzero (true)
35 * if the file can be opened and is a PNG, 0 (false) otherwise.
36 *
37 * If this call is successful, and you are going to keep the file open,
38 * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
39 * you have created the png_ptr, so that libpng knows your application
40 * has read that many bytes from the start of the file.  Make sure you
41 * don't call png_set_sig_bytes() with more than 8 bytes read or give it
42 * an incorrect number of bytes read, or you will either have read too
43 * many bytes (your fault), or you are telling libpng to read the wrong
44 * number of magic bytes (also your fault).
45 *
46 * Many applications already read the first 2 or 4 bytes from the start
47 * 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 * you have a PNG file, and call png_set_sig_bytes().
50 */
51#define PNG_BYTES_TO_CHECK 4
52int check_if_png(char *file_name, FILE **fp)
53{
54   char buf[PNG_BYTES_TO_CHECK];
55
56   /* Open the prospective PNG file. */
57   if ((*fp = fopen(file_name, "rb")) == NULL)
58      return 0;
59
60   /* Read in some of the signature bytes */
61   if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
62      return 0;
63
64   /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
65      Return nonzero (true) if they match */
66
67   return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
68}
69
70/* Read a PNG file.  You may want to return an error code if the read
71 * fails (depending upon the failure).  There are two "prototypes" given
72 * here - one where we are given the filename, and we need to open the
73 * file, and the other where we are given an open file (possibly with
74 * some or all of the magic bytes read - see comments above).
75 */
76#ifdef open_file /* prototype 1 */
77void read_png(char *file_name)  /* We need to open the file */
78{
79   png_structp png_ptr;
80   png_infop info_ptr;
81   unsigned int sig_read = 0;
82   png_uint_32 width, height;
83   int bit_depth, color_type, interlace_type;
84   FILE *fp;
85
86   if ((fp = fopen(file_name, "rb")) == NULL)
87      return (ERROR);
88#else no_open_file /* prototype 2 */
89void read_png(FILE *fp, unsigned int sig_read)  /* file is already open */
90{
91   png_structp png_ptr;
92   png_infop info_ptr;
93   png_uint_32 width, height;
94   int bit_depth, color_type, interlace_type;
95#endif no_open_file /* only use one prototype! */
96
97   /* Create and initialize the png_struct with the desired error handler
98    * functions.  If you want to use the default stderr and longjump method,
99    * you can supply NULL for the last three parameters.  We also supply the
100    * the compiler header file version, so that we know if the application
101    * was compiled with a compatible version of the library.  REQUIRED
102    */
103   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
104      png_voidp user_error_ptr, user_error_fn, user_warning_fn);
105
106   if (png_ptr == NULL)
107   {
108      fclose(fp);
109      return (ERROR);
110   }
111
112   /* Allocate/initialize the memory for image information.  REQUIRED. */
113   info_ptr = png_create_info_struct(png_ptr);
114   if (info_ptr == NULL)
115   {
116      fclose(fp);
117      png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
118      return (ERROR);
119   }
120
121   /* Set error handling if you are using the setjmp/longjmp method (this is
122    * the normal method of doing things with libpng).  REQUIRED unless you
123    * set up your own error handlers in the png_create_read_struct() earlier.
124    */
125
126   if (setjmp(png_jmpbuf(png_ptr)))
127   {
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);
130      fclose(fp);
131      /* If we get here, we had a problem reading the file */
132      return (ERROR);
133   }
134
135   /* One of the following I/O initialization methods is REQUIRED */
136#ifdef streams /* PNG file I/O method 1 */
137   /* Set up the input control if you are using standard C streams */
138   png_init_io(png_ptr, fp);
139
140#else no_streams /* PNG file I/O method 2 */
141   /* If you are using replacement read functions, instead of calling
142    * png_init_io() here you would call:
143    */
144   png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
145   /* where user_io_ptr is a structure you want available to the callbacks */
146#endif no_streams /* Use only one I/O method! */
147
148   /* If we have already read some of the signature */
149   png_set_sig_bytes(png_ptr, sig_read);
150
151#ifdef hilevel
152   /*
153    * If you have enough memory to read in the entire image at once,
154    * and you need to specify only transforms that can be controlled
155    * with one of the PNG_TRANSFORM_* bits (this presently excludes
156    * dithering, filling, setting background, and doing gamma
157    * adjustment), then you can read the entire image (including
158    * pixels) into the info structure with this call:
159    */
160   png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
161#else
162   /* OK, you're doing it the hard way, with the lower-level functions */
163
164   /* The call to png_read_info() gives us all of the information from the
165    * PNG file before the first IDAT (image data chunk).  REQUIRED
166    */
167   png_read_info(png_ptr, info_ptr);
168
169   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
170       &interlace_type, int_p_NULL, int_p_NULL);
171
172/* Set up the data transformations you want.  Note that these are all
173 * optional.  Only call them if you want/need them.  Many of the
174 * transformations only work on specific types of images, and many
175 * are mutually exclusive.
176 */
177
178   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
179   png_set_strip_16(png_ptr);
180
181   /* Strip alpha bytes from the input data without combining with the
182    * background (not recommended).
183    */
184   png_set_strip_alpha(png_ptr);
185
186   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
187    * byte into separate bytes (useful for paletted and grayscale images).
188    */
189   png_set_packing(png_ptr);
190
191   /* Change the order of packed pixels to least significant bit first
192    * (not useful if you are using png_set_packing). */
193   png_set_packswap(png_ptr);
194
195   /* Expand paletted colors into true RGB triplets */
196   if (color_type == PNG_COLOR_TYPE_PALETTE)
197      png_set_palette_rgb(png_ptr);
198
199   /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
200   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
201      png_set_gray_1_2_4_to_8(png_ptr);
202
203   /* Expand paletted or RGB images with transparency to full alpha channels
204    * so the data will be available as RGBA quartets.
205    */
206   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
207      png_set_tRNS_to_alpha(png_ptr);
208
209   /* Set the background color to draw transparent and alpha images over.
210    * It is possible to set the red, green, and blue components directly
211    * for paletted images instead of supplying a palette index.  Note that
212    * even if the PNG file supplies a background, you are not required to
213    * use it - you should use the (solid) application background if it has one.
214    */
215
216   png_color_16 my_background, *image_background;
217
218   if (png_get_bKGD(png_ptr, info_ptr, &image_background))
219      png_set_background(png_ptr, image_background,
220                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
221   else
222      png_set_background(png_ptr, &my_background,
223                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
224
225   /* Some suggestions as to how to get a screen gamma value */
226
227   /* Note that screen gamma is the display_exponent, which includes
228    * the CRT_exponent and any correction for viewing conditions */
229   if (/* We have a user-defined screen gamma value */)
230   {
231      screen_gamma = user-defined screen_gamma;
232   }
233   /* This is one way that applications share the same screen gamma value */
234   else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
235   {
236      screen_gamma = atof(gamma_str);
237   }
238   /* If we don't have another value */
239   else
240   {
241      screen_gamma = 2.2;  /* A good guess for a PC monitors in a dimly
242                              lit room */
243      screen_gamma = 1.7 or 1.0;  /* A good guess for Mac systems */
244   }
245
246   /* Tell libpng to handle the gamma conversion for you.  The final call
247    * is a good guess for PC generated images, but it should be configurable
248    * by the user at run time by the user.  It is strongly suggested that
249    * your application support gamma correction.
250    */
251
252   int intent;
253
254   if (png_get_sRGB(png_ptr, info_ptr, &intent))
255      png_set_gamma(png_ptr, screen_gamma, 0.45455);
256   else
257   {
258      double image_gamma;
259      if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
260         png_set_gamma(png_ptr, screen_gamma, image_gamma);
261      else
262         png_set_gamma(png_ptr, screen_gamma, 0.45455);
263   }
264
265   /* Dither RGB files down to 8 bit palette or reduce palettes
266    * to the number of colors available on your screen.
267    */
268   if (color_type & PNG_COLOR_MASK_COLOR)
269   {
270      int num_palette;
271      png_colorp palette;
272
273      /* This reduces the image to the application supplied palette */
274      if (/* we have our own palette */)
275      {
276         /* An array of colors to which the image should be dithered */
277         png_color std_color_cube[MAX_SCREEN_COLORS];
278
279         png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
280            MAX_SCREEN_COLORS, png_uint_16p_NULL, 0);
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))
284      {
285         png_uint_16p histogram = NULL;
286
287         png_get_hIST(png_ptr, info_ptr, &histogram);
288
289         png_set_dither(png_ptr, palette, num_palette,
290                        max_screen_colors, histogram, 0);
291      }
292   }
293
294   /* invert monochrome files to have 0 as white and 1 as black */
295   png_set_invert_mono(png_ptr);
296
297   /* If you want to shift the pixel values from the range [0,255] or
298    * [0,65535] to the original [0,7] or [0,31], or whatever range the
299    * colors were originally in:
300    */
301   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
302   {
303      png_color_8p sig_bit;
304
305      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
306      png_set_shift(png_ptr, sig_bit);
307   }
308
309   /* flip the RGB pixels to BGR (or RGBA to BGRA) */
310   if (color_type & PNG_COLOR_MASK_COLOR)
311      png_set_bgr(png_ptr);
312
313   /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
314   png_set_swap_alpha(png_ptr);
315
316   /* swap bytes of 16 bit files to least significant byte first */
317   png_set_swap(png_ptr);
318
319   /* Add filler (or alpha) byte (before/after each RGB triplet) */
320   png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
321
322   /* Turn on interlace handling.  REQUIRED if you are not using
323    * png_read_image().  To see how to handle interlacing passes,
324    * see the png_read_row() method below:
325    */
326   number_passes = png_set_interlace_handling(png_ptr);
327
328   /* Optional call to gamma correct and add the background to the palette
329    * and update info structure.  REQUIRED if you are expecting libpng to
330    * update the palette for you (ie you selected such a transform above).
331    */
332   png_read_update_info(png_ptr, info_ptr);
333
334   /* Allocate the memory to hold the image using the fields of info_ptr. */
335
336   /* The easiest way to read the image: */
337   png_bytep row_pointers[height];
338
339   for (row = 0; row < height; row++)
340   {
341      row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
342         info_ptr));
343   }
344
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 */
347   png_read_image(png_ptr, row_pointers);
348
349#else no_entire /* Read the image one or more scanlines at a time */
350   /* The other way to read images - deal with interlacing: */
351
352   for (pass = 0; pass < number_passes; pass++)
353   {
354#ifdef single /* Read the image a single row at a time */
355      for (y = 0; y < height; y++)
356      {
357         png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1);
358      }
359
360#else no_single /* Read the image several rows at a time */
361      for (y = 0; y < height; y += number_of_rows)
362      {
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 */
370      }
371
372      /* if you want to display the image after every pass, do
373         so here */
374#endif no_single /* use only one of these two methods */
375   }
376#endif no_entire /* use only one of these two methods */
377
378   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
379   png_read_end(png_ptr, info_ptr);
380#endif hilevel
381
382   /* At this point you have read the entire image */
383
384   /* clean up after the read, and free any memory allocated - REQUIRED */
385   png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
386
387   /* close the file */
388   fclose(fp);
389
390   /* that's it */
391   return (OK);
392}
393
394/* progressively read a file */
395
396int
397initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
398{
399   /* Create and initialize the png_struct with the desired error handler
400    * functions.  If you want to use the default stderr and longjump method,
401    * you can supply NULL for the last three parameters.  We also check that
402    * the library version is compatible in case we are using dynamically
403    * linked libraries.
404    */
405   *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
406       png_voidp user_error_ptr, user_error_fn, user_warning_fn);
407
408   if (*png_ptr == NULL)
409   {
410      *info_ptr = NULL;
411      return (ERROR);
412   }
413
414   *info_ptr = png_create_info_struct(png_ptr);
415
416   if (*info_ptr == NULL)
417   {
418      png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL);
419      return (ERROR);
420   }
421
422   if (setjmp(png_jmpbuf((*png_ptr))))
423   {
424      png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL);
425      return (ERROR);
426   }
427
428   /* This one's new.  You will need to provide all three
429    * function callbacks, even if you aren't using them all.
430    * If you aren't using all functions, you can specify NULL
431    * parameters.  Even when all three functions are NULL,
432    * you need to call png_set_progressive_read_fn().
433    * These functions shouldn't be dependent on global or
434    * static variables if you are decoding several images
435    * simultaneously.  You should store stream specific data
436    * in a separate struct, given as the second parameter,
437    * and retrieve the pointer from inside the callbacks using
438    * the function png_get_progressive_ptr(png_ptr).
439    */
440   png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
441      info_callback, row_callback, end_callback);
442
443   return (OK);
444}
445
446int
447process_data(png_structp *png_ptr, png_infop *info_ptr,
448   png_bytep buffer, png_uint_32 length)
449{
450   if (setjmp(png_jmpbuf((*png_ptr))))
451   {
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);
455   }
456
457   /* This one's new also.  Simply give it chunks of data as
458    * they arrive from the data stream (in order, of course).
459    * On Segmented machines, don't give it any more than 64K.
460    * The library seems to run fine with sizes of 4K, although
461    * you can give it much less if necessary (I assume you can
462    * give it chunks of 1 byte, but I haven't tried with less
463    * than 256 bytes yet).  When this function returns, you may
464    * want to display any rows that were generated in the row
465    * callback, if you aren't already displaying them there.
466    */
467   png_process_data(*png_ptr, *info_ptr, buffer, length);
468   return (OK);
469}
470
471info_callback(png_structp png_ptr, png_infop info)
472{
473/* do any setup here, including setting any of the transformations
474 * mentioned in the Reading PNG files section.  For now, you _must_
475 * call either png_start_read_image() or png_read_update_info()
476 * after all the transformations are set (even if you don't set
477 * any).  You may start getting rows before png_process_data()
478 * returns, so this is your last chance to prepare for that.
479 */
480}
481
482row_callback(png_structp png_ptr, png_bytep new_row,
483   png_uint_32 row_num, int pass)
484{
485/*
486 * This function is called for every row in the image.  If the
487 * image is interlaced, and you turned on the interlace handler,
488 * this function will be called for every row in every pass.
489 *
490 * In this function you will receive a pointer to new row data from
491 * libpng called new_row that is to replace a corresponding row (of
492 * the same data format) in a buffer allocated by your application.
493 *
494 * The new row data pointer new_row may be NULL, indicating there is
495 * no new data to be replaced (in cases of interlace loading).
496 *
497 * If new_row is not NULL then you need to call
498 * png_progressive_combine_row() to replace the corresponding row as
499 * shown below:
500 */
501   /* Check if row_num is in bounds. */
502   if((row_num >= 0) && (row_num < height))
503   {
504     /* Get pointer to corresponding row in our
505      * PNG read buffer.
506      */
507     png_bytep old_row = ((png_bytep *)our_data)[row_num];
508
509     /* If both rows are allocated then copy the new row
510      * data to the corresponding row data.
511      */
512     if((old_row != NULL) && (new_row != NULL))
513     png_progressive_combine_row(png_ptr, old_row, new_row);
514   }
515/*
516 * The rows and passes are called in order, so you don't really
517 * need the row_num and pass, but I'm supplying them because it
518 * may make your life easier.
519 *
520 * For the non-NULL rows of interlaced images, you must call
521 * png_progressive_combine_row() passing in the new row and the
522 * old row, as demonstrated above.  You can call this function for
523 * NULL rows (it will just return) and for non-interlaced images
524 * (it just does the png_memcpy for you) if it will make the code
525 * easier.  Thus, you can just do this for all cases:
526 */
527
528   png_progressive_combine_row(png_ptr, old_row, new_row);
529
530/* where old_row is what was displayed for previous rows.  Note
531 * that the first pass (pass == 0 really) will completely cover
532 * the old row, so the rows do not have to be initialized.  After
533 * the first pass (and only for interlaced images), you will have
534 * to pass the current row as new_row, and the function will combine
535 * the old row and the new row.
536 */
537}
538
539end_callback(png_structp png_ptr, png_infop info)
540{
541/* this function is called when the whole image has been read,
542 * including any chunks after the image (up to and including
543 * the IEND).  You will usually have the same info chunk as you
544 * had in the header, although some data may have been added
545 * to the comments and time fields.
546 *
547 * Most people won't do much here, perhaps setting a flag that
548 * marks the image as finished.
549 */
550}
551
552/* write a png file */
553void write_png(char *file_name /* , ... other image information ... */)
554{
555   FILE *fp;
556   png_structp png_ptr;
557   png_infop info_ptr;
558   png_colorp palette;
559
560   /* open the file */
561   fp = fopen(file_name, "wb");
562   if (fp == NULL)
563      return (ERROR);
564
565   /* Create and initialize the png_struct with the desired error handler
566    * functions.  If you want to use the default stderr and longjump method,
567    * you can supply NULL for the last three parameters.  We also check that
568    * the library version is compatible with the one used at compile time,
569    * in case we are using dynamically linked libraries.  REQUIRED.
570    */
571   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
572      png_voidp user_error_ptr, user_error_fn, user_warning_fn);
573
574   if (png_ptr == NULL)
575   {
576      fclose(fp);
577      return (ERROR);
578   }
579
580   /* Allocate/initialize the image information data.  REQUIRED */
581   info_ptr = png_create_info_struct(png_ptr);
582   if (info_ptr == NULL)
583   {
584      fclose(fp);
585      png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
586      return (ERROR);
587   }
588
589   /* Set error handling.  REQUIRED if you aren't supplying your own
590    * error handling functions in the png_create_write_struct() call.
591    */
592   if (setjmp(png_jmpbuf(png_ptr)))
593   {
594      /* If we get here, we had a problem reading the file */
595      fclose(fp);
596      png_destroy_write_struct(&png_ptr, &info_ptr);
597      return (ERROR);
598   }
599
600   /* One of the following I/O initialization functions is REQUIRED */
601#ifdef streams /* I/O initialization method 1 */
602   /* set up the output control if you are using standard C streams */
603   png_init_io(png_ptr, fp);
604#else no_streams /* I/O initialization method 2 */
605   /* If you are using replacement read functions, instead of calling
606    * png_init_io() here you would call */
607   png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn,
608      user_IO_flush_function);
609   /* where user_io_ptr is a structure you want available to the callbacks */
610#endif no_streams /* only use one initialization method */
611
612#ifdef hilevel
613   /* This is the easy way.  Use it if you already have all the
614    * image info living info in the structure.  You could "|" many
615    * PNG_TRANSFORM flags into the png_transforms integer here.
616    */
617   png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
618#else
619   /* This is the hard way */
620
621   /* Set the image information here.  Width and height are up to 2^31,
622    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
623    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
624    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
625    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
626    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
627    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
628    */
629   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???,
630      PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
631
632   /* set the palette if there is one.  REQUIRED for indexed-color images */
633   palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
634             * sizeof (png_color));
635   /* ... set palette colors ... */
636   png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
637   /* You must not free palette here, because png_set_PLTE only makes a link to
638      the palette that you malloced.  Wait until you are about to destroy
639      the png structure. */
640
641   /* optional significant bit chunk */
642   /* if we are dealing with a grayscale image then */
643   sig_bit.gray = true_bit_depth;
644   /* otherwise, if we are dealing with a color image then */
645   sig_bit.red = true_red_bit_depth;
646   sig_bit.green = true_green_bit_depth;
647   sig_bit.blue = true_blue_bit_depth;
648   /* if the image has an alpha channel then */
649   sig_bit.alpha = true_alpha_bit_depth;
650   png_set_sBIT(png_ptr, info_ptr, sig_bit);
651
652
653   /* Optional gamma chunk is strongly suggested if you have any guess
654    * as to the correct gamma of the image.
655    */
656   png_set_gAMA(png_ptr, info_ptr, gamma);
657
658   /* Optionally write comments into the image */
659   text_ptr[0].key = "Title";
660   text_ptr[0].text = "Mona Lisa";
661   text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
662   text_ptr[1].key = "Author";
663   text_ptr[1].text = "Leonardo DaVinci";
664   text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
665   text_ptr[2].key = "Description";
666   text_ptr[2].text = "<long text>";
667   text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
668#ifdef PNG_iTXt_SUPPORTED
669   text_ptr[0].lang = NULL;
670   text_ptr[1].lang = NULL;
671   text_ptr[2].lang = NULL;
672#endif
673   png_set_text(png_ptr, info_ptr, text_ptr, 3);
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 */
678
679   /* Write the file header information.  REQUIRED */
680   png_write_info(png_ptr, info_ptr);
681
682   /* If you want, you can write the info in two steps, in case you need to
683    * write your private chunk ahead of PLTE:
684    *
685    *   png_write_info_before_PLTE(write_ptr, write_info_ptr);
686    *   write_my_chunk();
687    *   png_write_info(png_ptr, info_ptr);
688    *
689    * However, given the level of known- and unknown-chunk support in 1.1.0
690    * and up, this should no longer be necessary.
691    */
692
693   /* Once we write out the header, the compression type on the text
694    * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
695    * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
696    * at the end.
697    */
698
699   /* set up the transformations you want.  Note that these are
700    * all optional.  Only call them if you want them.
701    */
702
703   /* invert monochrome pixels */
704   png_set_invert_mono(png_ptr);
705
706   /* Shift the pixels up to a legal bit depth and fill in
707    * as appropriate to correctly scale the image.
708    */
709   png_set_shift(png_ptr, &sig_bit);
710
711   /* pack pixels into bytes */
712   png_set_packing(png_ptr);
713
714   /* swap location of alpha bytes from ARGB to RGBA */
715   png_set_swap_alpha(png_ptr);
716
717   /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
718    * RGB (4 channels -> 3 channels). The second parameter is not used.
719    */
720   png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
721
722   /* flip BGR pixels to RGB */
723   png_set_bgr(png_ptr);
724
725   /* swap bytes of 16-bit files to most significant byte first */
726   png_set_swap(png_ptr);
727
728   /* swap bits of 1, 2, 4 bit packed pixel formats */
729   png_set_packswap(png_ptr);
730
731   /* turn on interlace handling if you are not using png_write_image() */
732   if (interlacing)
733      number_passes = png_set_interlace_handling(png_ptr);
734   else
735      number_passes = 1;
736
737   /* The easiest way to write the image (you may have a different memory
738    * layout, however, so choose what fits your needs best).  You need to
739    * use the first method if you aren't handling interlacing yourself.
740    */
741   png_uint_32 k, height, width;
742   png_byte image[height][width*bytes_per_pixel];
743   png_bytep row_pointers[height];
744   for (k = 0; k < height; k++)
745     row_pointers[k] = image + k*width*bytes_per_pixel;
746
747   /* One of the following output methods is REQUIRED */
748#ifdef entire /* write out the entire image data in one call */
749   png_write_image(png_ptr, row_pointers);
750
751   /* the other way to write the image - deal with interlacing */
752
753#else no_entire /* write out the image data by one or more scanlines */
754   /* The number of passes is either 1 for non-interlaced images,
755    * or 7 for interlaced images.
756    */
757   for (pass = 0; pass < number_passes; pass++)
758   {
759      /* Write a few rows at a time. */
760      png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows);
761
762      /* If you are only writing one row at a time, this works */
763      for (y = 0; y < height; y++)
764      {
765         png_write_rows(png_ptr, &row_pointers[y], 1);
766      }
767   }
768#endif no_entire /* use only one output method */
769
770   /* You can write optional chunks like tEXt, zTXt, and tIME at the end
771    * as well.  Shouldn't be necessary in 1.1.0 and up as all the public
772    * chunks are supported and you can use png_set_unknown_chunks() to
773    * register unknown chunks into the info structure to be written out.
774    */
775
776   /* It is REQUIRED to call this to finish writing the rest of the file */
777   png_write_end(png_ptr, info_ptr);
778#endif hilevel
779
780   /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
781      as recommended in versions 1.0.5m and earlier of this example; if
782      libpng mallocs info_ptr->palette, libpng will free it).  If you
783      allocated it with malloc() instead of png_malloc(), use free() instead
784      of png_free(). */
785   png_free(png_ptr, palette);
786   palette=NULL;
787
788   /* Similarly, if you png_malloced any data that you passed in with
789      png_set_something(), such as a hist or trans array, free it here,
790      when you can be sure that libpng is through with it. */
791   png_free(png_ptr, trans);
792   trans=NULL;
793
794   /* clean up after the write, and free any memory allocated */
795   png_destroy_write_struct(&png_ptr, &info_ptr);
796
797   /* close the file */
798   fclose(fp);
799
800   /* that's it */
801   return (OK);
802}
803
804#endif /* if 0 */
Note: See TracBrowser for help on using the repository browser.