blob: 65e615d7e5ec1545fdb901dacf597ed33aa5de0a [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001/* example.c - an example of using libpng */
2
3/* this is an example of how to use libpng to read and write
4 png files. The file libpng.txt is much more verbose then
5 this. If you have not read it, do so first. This was
6 designed to be a starting point of an implementation.
7 This is not officially part of libpng, and therefore
8 does not require a copyright notice.
Guy Schalnat51f0eb41995-09-26 05:22:39 -05009
10 This file does not currently compile, because it is missing
11 certain parts, like allocating memory to hold an image.
12 You will have to supply these parts to get it to compile.
Guy Schalnat0d580581995-07-20 02:43:20 -050013 */
14
15#include <png.h>
16
17/* check to see if a file is a png file using png_check_sig() */
Guy Schalnat6d764711995-12-19 03:22:19 -060018int check_png(char * file_name)
Guy Schalnat0d580581995-07-20 02:43:20 -050019{
20 FILE *fp;
21 char buf[8];
22 int ret;
23
24 fp = fopen(file_name, "rb");
25 if (!fp)
26 return 0;
27 ret = fread(buf, 1, 8, fp);
28 fclose(fp);
29
30 if (ret != 8)
31 return 0;
32
33 ret = png_check_sig(buf, 8);
34
35 return (ret);
36}
37
38/* read a png file. You may want to return an error code if the read
39 fails (depending upon the failure). */
40void read_png(char *file_name)
41{
42 FILE *fp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060043 png_structp png_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -060044 png_infop info_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -050045
46 /* open the file */
47 fp = fopen(file_name, "rb");
48 if (!fp)
49 return;
50
Guy Schalnate5a37791996-06-05 15:50:50 -050051 /* Create and initialize the png_struct with the desired error handler
52 functions. If you want to use the default stderr and longjump method,
53 you can supply NULL for the last three parameters. We also check that
54 the header file is compatible with the library version.
55 */
56 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
57 (void *)user_error_ptr, user_error_fn, user_warning_fn);
58
Guy Schalnat0d580581995-07-20 02:43:20 -050059 if (!png_ptr)
60 {
61 fclose(fp);
62 return;
63 }
64
Guy Schalnate5a37791996-06-05 15:50:50 -050065 info_ptr = png_create_info_struct();
Guy Schalnat0d580581995-07-20 02:43:20 -050066 if (!info_ptr)
67 {
68 fclose(fp);
Guy Schalnate5a37791996-06-05 15:50:50 -050069 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -050070 return;
71 }
72
Guy Schalnate5a37791996-06-05 15:50:50 -050073 /* set error handling if you are using the setjmp/longjmp method */
Guy Schalnat0d580581995-07-20 02:43:20 -050074 if (setjmp(png_ptr->jmpbuf))
75 {
Guy Schalnate5a37791996-06-05 15:50:50 -050076 /* Free all of the memory associated with the png_ptr and info_ptr */
77 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -050078 fclose(fp);
Guy Schalnat0d580581995-07-20 02:43:20 -050079 /* If we get here, we had a problem reading the file */
80 return;
81 }
82
Guy Schalnat69b14481996-01-10 02:56:49 -060083 /* set up the input control if you are using standard C streams */
Guy Schalnat0d580581995-07-20 02:43:20 -050084 png_init_io(png_ptr, fp);
85
Guy Schalnate5a37791996-06-05 15:50:50 -050086 /* if you are using replacement read functions, instead of calling
87 png_init_io() here you would call */
88 png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
89 /* where user_io_ptr is a structure you want available to the callbacks */
Guy Schalnat69b14481996-01-10 02:56:49 -060090
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060091 /* read the file information */
92 png_read_info(png_ptr, info_ptr);
Guy Schalnat69b14481996-01-10 02:56:49 -060093
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060094 /* set up the transformations you want. Note that these are
Guy Schalnat0d580581995-07-20 02:43:20 -050095 all optional. Only call them if you want them */
96
Guy Schalnate5a37791996-06-05 15:50:50 -050097 /* expand paletted colors into true RGB triplets */
Guy Schalnat51f0eb41995-09-26 05:22:39 -050098 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -050099 png_set_expand(png_ptr);
100
101 /* expand grayscale images to the full 8 bits */
Guy Schalnate5a37791996-06-05 15:50:50 -0500102 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -0500103 png_set_expand(png_ptr);
104
Guy Schalnate5a37791996-06-05 15:50:50 -0500105 /* expand paletted or RGB images with transparency to full alpha channels
106 * so the data will be available as RGBA quartets */
Guy Schalnat0d580581995-07-20 02:43:20 -0500107 if (info_ptr->valid & PNG_INFO_tRNS)
108 png_set_expand(png_ptr);
109
110 /* Set the background color to draw transparent and alpha
Guy Schalnate5a37791996-06-05 15:50:50 -0500111 images over. It is possible to set the red, green, and blue
112 components directly for paletted images. */
113
Guy Schalnat0d580581995-07-20 02:43:20 -0500114 png_color_16 my_background;
115
116 if (info_ptr->valid & PNG_INFO_bKGD)
117 png_set_background(png_ptr, &(info_ptr->background),
Guy Schalnate5a37791996-06-05 15:50:50 -0500118 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600119 else
120 png_set_background(png_ptr, &my_background,
Guy Schalnate5a37791996-06-05 15:50:50 -0500121 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500122
123 /* tell libpng to handle the gamma conversion for you */
124 if (info_ptr->valid & PNG_INFO_gAMA)
125 png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
126 else
127 png_set_gamma(png_ptr, screen_gamma, 0.45);
128
Guy Schalnate5a37791996-06-05 15:50:50 -0500129 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
Guy Schalnat0d580581995-07-20 02:43:20 -0500130 if (info_ptr->bit_depth == 16)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600131 png_set_strip_16(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500132
Guy Schalnate5a37791996-06-05 15:50:50 -0500133 /* dither rgb files down to 8 bit palette & reduce palettes
Guy Schalnat0d580581995-07-20 02:43:20 -0500134 to the number of colors available on your screen */
135 if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
136 {
137 if (info_ptr->valid & PNG_INFO_PLTE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500138 png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette,
139 max_screen_colors, info_ptr->histogram);
Guy Schalnat0d580581995-07-20 02:43:20 -0500140 else
141 {
142 png_color std_color_cube[MAX_SCREEN_COLORS] =
143 {/* ... colors ... */};
144
145 png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
146 MAX_SCREEN_COLORS, NULL);
147 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600148 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500149
Guy Schalnate5a37791996-06-05 15:50:50 -0500150 /* invert monocrome files to have 0 as white and 1 as black */
151 if (info_ptr->bit_depth == 1 && info_ptr->color_type == PNG_COLOR_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -0500152 png_set_invert(png_ptr);
153
154 /* shift the pixels down to their true bit depth */
Guy Schalnat6d764711995-12-19 03:22:19 -0600155 if (info_ptr->valid & PNG_INFO_sBIT &&
156 info_ptr->bit_depth > info_ptr->sig_bit)
Guy Schalnat0d580581995-07-20 02:43:20 -0500157 png_set_shift(png_ptr, &(info_ptr->sig_bit));
158
Guy Schalnate5a37791996-06-05 15:50:50 -0500159 /* pack multiple pixels with bit depths of 1, 2, and 4 into bytes
160 (useful only for paletted and grayscale images) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500161 if (info_ptr->bit_depth < 8)
162 png_set_packing(png_ptr);
163
164 /* flip the rgb pixels to bgr */
165 if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600166 info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -0500167 png_set_bgr(png_ptr);
168
169 /* swap bytes of 16 bit files to least significant bit first */
170 if (info_ptr->bit_depth == 16)
171 png_set_swap(png_ptr);
172
Guy Schalnate5a37791996-06-05 15:50:50 -0500173 /* add a filler byte to RGB files (before or after each RGB triplet) */
174 if (info_ptr->bit_depth == 8 && info_ptr->color_type == PNG_COLOR_TYPE_RGB)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500175 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
Guy Schalnat0d580581995-07-20 02:43:20 -0500176
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500177 /* turn on interlace handling if you are not using png_read_image() */
Guy Schalnate5a37791996-06-05 15:50:50 -0500178 number_passes = png_set_interlace_handling(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500179
Guy Schalnate5a37791996-06-05 15:50:50 -0500180 /* optional call to gamma correct and add the background to the palette
181 and update info structure. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500182 png_read_update_info(png_ptr, info_ptr);
183
184 /* allocate the memory to hold the image using the fields
185 of png_info. */
186
187 /* the easiest way to read the image */
Guy Schalnat6d764711995-12-19 03:22:19 -0600188 png_bytep row_pointers[height];
Guy Schalnate5a37791996-06-05 15:50:50 -0500189
190 for (row = 0; row < height; row++)
191 {
192 row_pointers[row] = malloc(info_ptr->rowbytes);
193 }
194
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500195 png_read_image(png_ptr, row_pointers);
196
197 /* the other way to read images - deal with interlacing */
198
Guy Schalnat0d580581995-07-20 02:43:20 -0500199 for (pass = 0; pass < number_passes; pass++)
200 {
201 /* Read the image using the "sparkle" effect. */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600202 png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
Guy Schalnat0d580581995-07-20 02:43:20 -0500203
204 /* If you are only reading on row at a time, this works */
205 for (y = 0; y < height; y++)
206 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600207 png_bytep row_pointers = row[y];
Guy Schalnat0d580581995-07-20 02:43:20 -0500208 png_read_rows(png_ptr, &row_pointers, NULL, 1);
209 }
210
211 /* to get the rectangle effect, use the third parameter */
212 png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
213
214 /* if you want to display the image after every pass, do
215 so here */
216 }
217
Guy Schalnate5a37791996-06-05 15:50:50 -0500218 /* read the rest of the file, getting any additional chunks in info_ptr */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600219 png_read_end(png_ptr, info_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500220
221 /* clean up after the read, and free any memory allocated */
Guy Schalnate5a37791996-06-05 15:50:50 -0500222 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500223
224 /* close the file */
225 fclose(fp);
226
227 /* that's it */
228 return;
229}
230
Guy Schalnat6d764711995-12-19 03:22:19 -0600231/* progressively read a file */
232
Guy Schalnat6d764711995-12-19 03:22:19 -0600233int
Guy Schalnate5a37791996-06-05 15:50:50 -0500234initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
Guy Schalnat6d764711995-12-19 03:22:19 -0600235{
Guy Schalnate5a37791996-06-05 15:50:50 -0500236 /* Create and initialize the png_struct with the desired error handler
237 functions. If you want to use the default stderr and longjump method,
238 you can supply NULL for the last three parameters. We also check that
239 the library version is compatible in case we are using dynamically
240 linked libraries.
241 */
242 *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
243 (void *)user_error_ptr, user_error_fn, user_warning_fn);
244
245 if (! *png_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600246 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500247 *info_ptr = NULL;
248 return ERROR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600249 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600250
Guy Schalnate5a37791996-06-05 15:50:50 -0500251 *info_ptr = png_create_info_struct(png_ptr);
252
253 if (! *info_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600254 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500255 png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
256 return ERROR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600257 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600258
Guy Schalnate5a37791996-06-05 15:50:50 -0500259 if (setjmp((*png_ptr)->jmpbuf))
260 {
261 png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
262 return ERROR;
263 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600264
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600265 /* this one's new. You will need to provide all three
266 function callbacks, even if you aren't using them all.
Guy Schalnate5a37791996-06-05 15:50:50 -0500267 These functions shouldn't be dependent on global or
268 static variables if you are decoding several images
269 simultaneously. You should store stream specific data
270 in a separate struct, given as the second parameter,
271 and retrieve the pointer from inside the callbacks using
272 the function png_get_progressive_ptr(png_ptr). */
273 png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600274 info_callback, row_callback, end_callback);
Guy Schalnat6d764711995-12-19 03:22:19 -0600275
Guy Schalnate5a37791996-06-05 15:50:50 -0500276 return OK;
Guy Schalnat6d764711995-12-19 03:22:19 -0600277}
278
279int
Guy Schalnate5a37791996-06-05 15:50:50 -0500280process_data(png_structp *png_ptr, png_infop *info_ptr,
281 png_bytep buffer, png_uint_32 length)
Guy Schalnat6d764711995-12-19 03:22:19 -0600282{
Guy Schalnate5a37791996-06-05 15:50:50 -0500283 if (setjmp((*png_ptr)->jmpbuf))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600284 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500285 /* Free the png_ptr and info_ptr memory on error */
286 png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
287 return ERROR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600288 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600289
Guy Schalnate5a37791996-06-05 15:50:50 -0500290 /* this one's new also. Simply give it chunks of data as
291 they arrive from the data stream (in order, of course).
292 On Segmented machines, don't give it any more than 64K.
293 The library seems to run fine with sizes of 4K, although
294 you can give it much less if necessary (I assume you can
295 give it chunks of 1 byte, but I haven't tried with less
296 than 256 bytes yet). When this function returns, you may
297 want to display any rows that were generated in the row
298 callback, if you aren't already displaying them there. */
299 png_process_data(*png_ptr, *info_ptr, buffer, length);
300 return OK;
Guy Schalnat6d764711995-12-19 03:22:19 -0600301}
302
303info_callback(png_structp png_ptr, png_infop info)
304{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600305/* do any setup here, including setting any of the transformations
306 mentioned in the Reading PNG files section. For now, you _must_
307 call either png_start_read_image() or png_read_update_info()
308 after all the transformations are set (even if you don't set
309 any). You may start getting rows before png_process_data()
310 returns, so this is your last chance to prepare for that. */
Guy Schalnat6d764711995-12-19 03:22:19 -0600311}
312
313row_callback(png_structp png_ptr, png_bytep new_row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600314 png_uint_32 row_num, int pass)
Guy Schalnat6d764711995-12-19 03:22:19 -0600315{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600316/* this function is called for every row in the image. If the
317 image is interlacing, and you turned on the interlace handler,
318 this function will be called for every row in every pass.
319 Some of these rows will not be changed from the previous pass.
320 When the row is not changed, the new_row variable will be NULL.
321 The rows and passes are called in order, so you don't really
322 need the row_num and pass, but I'm supplying them because it
323 may make your life easier.
Guy Schalnat6d764711995-12-19 03:22:19 -0600324
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600325 For the non-NULL rows of interlaced images, you must call
326 png_progressive_combine_row() passing in the row and the
327 old row. You can call this function for NULL rows (it will
328 just return) and for non-interlaced images (it just does the
329 memcpy for you) if it will make the code easier. Thus, you
330 can just do this for all cases: */
Guy Schalnat6d764711995-12-19 03:22:19 -0600331
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600332 png_progressive_combine_row(png_ptr, old_row, new_row);
Guy Schalnat6d764711995-12-19 03:22:19 -0600333
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600334/* where old_row is what was displayed for previous rows. Note
335 that the first pass (pass == 0 really) will completely cover
336 the old row, so the rows do not have to be initialized. After
337 the first pass (and only for interlaced images), you will have
338 to pass the current row, and the function will combine the
339 old row and the new row. */
Guy Schalnat6d764711995-12-19 03:22:19 -0600340}
341
342end_callback(png_structp png_ptr, png_infop info)
343{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600344/* this function is called when the whole image has been read,
345 including any chunks after the image (up to and including
346 the IEND). You will usually have the same info chunk as you
347 had in the header, although some data may have been added
348 to the comments and time fields.
Guy Schalnat6d764711995-12-19 03:22:19 -0600349
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600350 Most people won't do much here, perhaps setting a flag that
351 marks the image as finished. */
Guy Schalnat6d764711995-12-19 03:22:19 -0600352}
353
Guy Schalnat0d580581995-07-20 02:43:20 -0500354/* write a png file */
355void write_png(char *file_name, ... other image information ...)
356{
357 FILE *fp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600358 png_structp png_ptr;
359 png_infop info_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500360
361 /* open the file */
362 fp = fopen(file_name, "wb");
363 if (!fp)
364 return;
365
Guy Schalnate5a37791996-06-05 15:50:50 -0500366 /* Create and initialize the png_struct with the desired error handler
367 functions. If you want to use the default stderr and longjump method,
368 you can supply NULL for the last three parameters. We also check that
369 the library version is compatible in case we are using dynamically
370 linked libraries.
371 */
372 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
373 (void *)user_error_ptr, user_error_fn, user_warning_fn);
374
Guy Schalnat0d580581995-07-20 02:43:20 -0500375 if (!png_ptr)
376 {
377 fclose(fp);
378 return;
379 }
380
Guy Schalnate5a37791996-06-05 15:50:50 -0500381 info_ptr = png_create_info_struct(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500382 if (!info_ptr)
383 {
384 fclose(fp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500385 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500386 return;
387 }
388
389 /* set error handling */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600390 if (setjmp(png_ptr->jmpbuf))
Guy Schalnat0d580581995-07-20 02:43:20 -0500391 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500392 /* If we get here, we had a problem reading the file */
Guy Schalnate5a37791996-06-05 15:50:50 -0500393 fclose(fp);
394 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500395 return;
396 }
397
Guy Schalnat69b14481996-01-10 02:56:49 -0600398 /* set up the output control if you are using standard C streams */
Guy Schalnat0d580581995-07-20 02:43:20 -0500399 png_init_io(png_ptr, fp);
400
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600401 /* if you are using replacement message functions, here you would call */
402 png_set_message_fn(png_ptr, (void *)msg_ptr, user_error_fn, user_warning_fn);
403 /* where msg_ptr is a structure you want available to the callbacks */
Guy Schalnat69b14481996-01-10 02:56:49 -0600404
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600405 /* set the file information here */
Guy Schalnat0d580581995-07-20 02:43:20 -0500406 info_ptr->width = ;
407 info_ptr->height = ;
408 etc.
409
410 /* set the palette if there is one */
411 info_ptr->valid |= PNG_INFO_PLTE;
412 info_ptr->palette = malloc(256 * sizeof (png_color));
413 info_ptr->num_palette = 256;
414 ... set palette colors ...
415
416 /* optional significant bit chunk */
417 info_ptr->valid |= PNG_INFO_sBIT;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600418 /* if we are dealing with a grayscale image then */
419 info_ptr->sig_bit.gray = true_bit_depth;
420 /* otherwise, if we are dealing with a color image then */
421 info_ptr->sig_bit.red = true_red_bit_depth;
422 info_ptr->sig_bit.green = true_green_bit_depth;
423 info_ptr->sig_bit.blue = true_blue_bit_depth;
424 /* if the image has an alpha channel then */
Guy Schalnat69b14481996-01-10 02:56:49 -0600425 info_ptr->sig_bit.alpha = true_alpha_bit_depth;
426
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600427 /* optional gamma chunk is strongly suggested if you have any guess
428 as to the correct gamma of the image */
429 info_ptr->valid |= PNG_INFO_gAMA;
Guy Schalnat0d580581995-07-20 02:43:20 -0500430 info_ptr->gamma = gamma;
431
Guy Schalnate5a37791996-06-05 15:50:50 -0500432 /* other optional chunks like cHRM, bKGD, tRNS, tEXt, tIME, oFFs, pHYs, */
Guy Schalnat0d580581995-07-20 02:43:20 -0500433
Guy Schalnate5a37791996-06-05 15:50:50 -0500434 /* write the file header information */
Guy Schalnat0d580581995-07-20 02:43:20 -0500435 png_write_info(png_ptr, info_ptr);
436
437 /* set up the transformations you want. Note that these are
438 all optional. Only call them if you want them */
439
440 /* invert monocrome pixels */
441 png_set_invert(png_ptr);
442
443 /* shift the pixels up to a legal bit depth and fill in
444 as appropriate to correctly scale the image */
445 png_set_shift(png_ptr, &(info_ptr->sig_bit));
446
447 /* pack pixels into bytes */
448 png_set_packing(png_ptr);
449
450 /* flip bgr pixels to rgb */
451 png_set_bgr(png_ptr);
452
453 /* swap bytes of 16 bit files to most significant bit first */
454 png_set_swap(png_ptr);
455
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500456 /* get rid of filler bytes, pack rgb into 3 bytes. The
457 filler number is not used. */
458 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
Guy Schalnat0d580581995-07-20 02:43:20 -0500459
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500460 /* turn on interlace handling if you are not using png_write_image() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500461 if (interlacing)
462 number_passes = png_set_interlace_handling(png_ptr);
463 else
464 number_passes = 1;
465
Guy Schalnate5a37791996-06-05 15:50:50 -0500466 /* the easiest way to write the image (you may choose to allocate the
467 memory differently, however) */
468 png_byte row_pointers[height][width];
469
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500470 png_write_image(png_ptr, row_pointers);
471
472 /* the other way to write the image - deal with interlacing */
473
Guy Schalnat0d580581995-07-20 02:43:20 -0500474 for (pass = 0; pass < number_passes; pass++)
475 {
476 /* Write a few rows at a time. */
477 png_write_rows(png_ptr, row_pointers, number_of_rows);
478
479 /* If you are only writing one row at a time, this works */
480 for (y = 0; y < height; y++)
481 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600482 png_bytep row_pointers = row[y];
Guy Schalnat0d580581995-07-20 02:43:20 -0500483 png_write_rows(png_ptr, &row_pointers, 1);
484 }
485 }
486
Guy Schalnate5a37791996-06-05 15:50:50 -0500487 /* You can write optional chunks like tEXt, tIME at the end as well.
488 * Note that if you wrote tEXt or zTXt chunks before the image, and
489 * you aren't writing out more at the end, you have to set
490 * info_ptr->num_text = 0 or they will be written out again.
491 */
492
Guy Schalnat0d580581995-07-20 02:43:20 -0500493 /* write the rest of the file */
494 png_write_end(png_ptr, info_ptr);
495
Guy Schalnat0d580581995-07-20 02:43:20 -0500496 /* if you malloced the palette, free it here */
497 if (info_ptr->palette)
498 free(info_ptr->palette);
499
Guy Schalnate5a37791996-06-05 15:50:50 -0500500 /* if you allocated any text comments, free them here */
501
502 /* clean up after the write, and free any memory allocated */
503 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500504
505 /* close the file */
506 fclose(fp);
507
508 /* that's it */
509 return;
510}
511