blob: 0903933a9912d76a2e6218dd65a58a2988b3e912 [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
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060017/* Check to see if a file is a png file using png_check_sig().
18
19 If this call is successful, and you are going to keep the file
20 open, you should call png_set_sig_bytes_read(png_ptr, 8);
21 once you have created the png_ptr, so that libpng knows it
22 doesn't have to read the signature again. Make sure you don't
23 call png_set_sig_bytes_read() with more than 8 bytes read or
24 give it an incorrect number of bytes read, or you will either
25 have read too many bytes (your fault), or you are telling libpng
26 to read the wrong number of magic bytes (also your fault). */
27int check_png(char *file_name, FILE **fp)
Guy Schalnat0d580581995-07-20 02:43:20 -050028{
Guy Schalnat0d580581995-07-20 02:43:20 -050029 char buf[8];
30 int ret;
31
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060032 *fp = fopen(file_name, "rb");
Guy Schalnat0d580581995-07-20 02:43:20 -050033 if (!fp)
34 return 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060035 ret = fread(buf, 1, 8, *fp);
Guy Schalnat0d580581995-07-20 02:43:20 -050036
37 if (ret != 8)
38 return 0;
39
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060040 /* Check the signature starting at byte 0, and check all 8 bytes */
41 ret = png_check_sig(buf, 0, 8);
Guy Schalnat0d580581995-07-20 02:43:20 -050042
43 return (ret);
44}
45
46/* read a png file. You may want to return an error code if the read
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060047 fails (depending upon the failure). There are two "prototypes" given
48 here - one where we are given the filename, and we need to open the
49 file, and the other where we are given an open file (possibly with
50 some or all of the magic bytes read - see above) and an opened file
51 for reading. */
52------- prototype 1 ----------
53void read_png(char *file_name) /* We need to open the file */
Guy Schalnat0d580581995-07-20 02:43:20 -050054{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060055 png_structp png_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -060056 png_infop info_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060057 FILE *fp;
Guy Schalnat0d580581995-07-20 02:43:20 -050058
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060059 if ((fp = fopen(file_name, "rb")) == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -050060 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060061------- prototype 2 ----------
62void read_png(FILE *fp, unsigned int sig_read) /* file is already open */
63{
64 png_structp png_ptr;
65 png_infop info_ptr;
66------- only use one! --------
Guy Schalnat0d580581995-07-20 02:43:20 -050067
Guy Schalnate5a37791996-06-05 15:50:50 -050068 /* Create and initialize the png_struct with the desired error handler
69 functions. If you want to use the default stderr and longjump method,
70 you can supply NULL for the last three parameters. We also check that
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060071 the header file is compatible with the library version. */
Guy Schalnate5a37791996-06-05 15:50:50 -050072 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
73 (void *)user_error_ptr, user_error_fn, user_warning_fn);
74
Guy Schalnat0d580581995-07-20 02:43:20 -050075 if (!png_ptr)
76 {
77 fclose(fp);
78 return;
79 }
80
Guy Schalnate5a37791996-06-05 15:50:50 -050081 info_ptr = png_create_info_struct();
Guy Schalnat0d580581995-07-20 02:43:20 -050082 if (!info_ptr)
83 {
84 fclose(fp);
Guy Schalnate5a37791996-06-05 15:50:50 -050085 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -050086 return;
87 }
88
Guy Schalnate5a37791996-06-05 15:50:50 -050089 /* set error handling if you are using the setjmp/longjmp method */
Guy Schalnat0d580581995-07-20 02:43:20 -050090 if (setjmp(png_ptr->jmpbuf))
91 {
Guy Schalnate5a37791996-06-05 15:50:50 -050092 /* Free all of the memory associated with the png_ptr and info_ptr */
93 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -050094 fclose(fp);
Guy Schalnat0d580581995-07-20 02:43:20 -050095 /* If we get here, we had a problem reading the file */
96 return;
97 }
98
Guy Schalnat69b14481996-01-10 02:56:49 -060099 /* set up the input control if you are using standard C streams */
Guy Schalnat0d580581995-07-20 02:43:20 -0500100 png_init_io(png_ptr, fp);
101
Guy Schalnate5a37791996-06-05 15:50:50 -0500102 /* if you are using replacement read functions, instead of calling
103 png_init_io() here you would call */
104 png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
105 /* where user_io_ptr is a structure you want available to the callbacks */
Guy Schalnat69b14481996-01-10 02:56:49 -0600106
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600107 /* if we have already read some of the signature from the beginning call */
108 png_set_sig_bytes_read(png_ptr, sig_read);
109
110 /* The call to png_read_info() gives us all of the information
111 from the PNG file before the first IDAT (image data chunk). */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600112 png_read_info(png_ptr, info_ptr);
Guy Schalnat69b14481996-01-10 02:56:49 -0600113
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600114 /* set up the transformations you want. Note that these are
Guy Schalnat0d580581995-07-20 02:43:20 -0500115 all optional. Only call them if you want them */
116
Guy Schalnate5a37791996-06-05 15:50:50 -0500117 /* expand paletted colors into true RGB triplets */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500118 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500119 png_set_expand(png_ptr);
120
121 /* expand grayscale images to the full 8 bits */
Guy Schalnate5a37791996-06-05 15:50:50 -0500122 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -0500123 png_set_expand(png_ptr);
124
Guy Schalnate5a37791996-06-05 15:50:50 -0500125 /* expand paletted or RGB images with transparency to full alpha channels
126 * so the data will be available as RGBA quartets */
Guy Schalnat0d580581995-07-20 02:43:20 -0500127 if (info_ptr->valid & PNG_INFO_tRNS)
128 png_set_expand(png_ptr);
129
130 /* Set the background color to draw transparent and alpha
Guy Schalnate5a37791996-06-05 15:50:50 -0500131 images over. It is possible to set the red, green, and blue
132 components directly for paletted images. */
133
Guy Schalnat0d580581995-07-20 02:43:20 -0500134 png_color_16 my_background;
135
136 if (info_ptr->valid & PNG_INFO_bKGD)
137 png_set_background(png_ptr, &(info_ptr->background),
Guy Schalnate5a37791996-06-05 15:50:50 -0500138 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600139 else
140 png_set_background(png_ptr, &my_background,
Guy Schalnate5a37791996-06-05 15:50:50 -0500141 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500142
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600143 /* tell libpng to handle the gamma conversion for you. We only
144 need the second call if the screen_gamma isn't the usual 2.2
145 or if it is controllable by the user. It may also be a good
146 idea to allow the user to set the file gamma if it is unknown. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500147 if (info_ptr->valid & PNG_INFO_gAMA)
148 png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
149 else
150 png_set_gamma(png_ptr, screen_gamma, 0.45);
151
Guy Schalnate5a37791996-06-05 15:50:50 -0500152 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
Guy Schalnat0d580581995-07-20 02:43:20 -0500153 if (info_ptr->bit_depth == 16)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600154 png_set_strip_16(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500155
Guy Schalnate5a37791996-06-05 15:50:50 -0500156 /* dither rgb files down to 8 bit palette & reduce palettes
Guy Schalnat0d580581995-07-20 02:43:20 -0500157 to the number of colors available on your screen */
158 if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
159 {
160 if (info_ptr->valid & PNG_INFO_PLTE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500161 png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette,
162 max_screen_colors, info_ptr->histogram);
Guy Schalnat0d580581995-07-20 02:43:20 -0500163 else
164 {
165 png_color std_color_cube[MAX_SCREEN_COLORS] =
166 {/* ... colors ... */};
167
168 png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
169 MAX_SCREEN_COLORS, NULL);
170 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600171 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500172
Guy Schalnate5a37791996-06-05 15:50:50 -0500173 /* invert monocrome files to have 0 as white and 1 as black */
174 if (info_ptr->bit_depth == 1 && info_ptr->color_type == PNG_COLOR_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -0500175 png_set_invert(png_ptr);
176
177 /* shift the pixels down to their true bit depth */
Guy Schalnat6d764711995-12-19 03:22:19 -0600178 if (info_ptr->valid & PNG_INFO_sBIT &&
179 info_ptr->bit_depth > info_ptr->sig_bit)
Guy Schalnat0d580581995-07-20 02:43:20 -0500180 png_set_shift(png_ptr, &(info_ptr->sig_bit));
181
Guy Schalnate5a37791996-06-05 15:50:50 -0500182 /* pack multiple pixels with bit depths of 1, 2, and 4 into bytes
183 (useful only for paletted and grayscale images) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500184 if (info_ptr->bit_depth < 8)
185 png_set_packing(png_ptr);
186
187 /* flip the rgb pixels to bgr */
188 if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600189 info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -0500190 png_set_bgr(png_ptr);
191
192 /* swap bytes of 16 bit files to least significant bit first */
193 if (info_ptr->bit_depth == 16)
194 png_set_swap(png_ptr);
195
Guy Schalnate5a37791996-06-05 15:50:50 -0500196 /* add a filler byte to RGB files (before or after each RGB triplet) */
197 if (info_ptr->bit_depth == 8 && info_ptr->color_type == PNG_COLOR_TYPE_RGB)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500198 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
Guy Schalnat0d580581995-07-20 02:43:20 -0500199
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500200 /* turn on interlace handling if you are not using png_read_image() */
Guy Schalnate5a37791996-06-05 15:50:50 -0500201 number_passes = png_set_interlace_handling(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500202
Guy Schalnate5a37791996-06-05 15:50:50 -0500203 /* optional call to gamma correct and add the background to the palette
204 and update info structure. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500205 png_read_update_info(png_ptr, info_ptr);
206
207 /* allocate the memory to hold the image using the fields
208 of png_info. */
209
210 /* the easiest way to read the image */
Guy Schalnat6d764711995-12-19 03:22:19 -0600211 png_bytep row_pointers[height];
Guy Schalnate5a37791996-06-05 15:50:50 -0500212
213 for (row = 0; row < height; row++)
214 {
215 row_pointers[row] = malloc(info_ptr->rowbytes);
216 }
217
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500218 png_read_image(png_ptr, row_pointers);
219
220 /* the other way to read images - deal with interlacing */
221
Guy Schalnat0d580581995-07-20 02:43:20 -0500222 for (pass = 0; pass < number_passes; pass++)
223 {
224 /* Read the image using the "sparkle" effect. */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600225 png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
Guy Schalnat0d580581995-07-20 02:43:20 -0500226
227 /* If you are only reading on row at a time, this works */
228 for (y = 0; y < height; y++)
229 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600230 png_bytep row_pointers = row[y];
Guy Schalnat0d580581995-07-20 02:43:20 -0500231 png_read_rows(png_ptr, &row_pointers, NULL, 1);
232 }
233
234 /* to get the rectangle effect, use the third parameter */
235 png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
236
237 /* if you want to display the image after every pass, do
238 so here */
239 }
240
Guy Schalnate5a37791996-06-05 15:50:50 -0500241 /* read the rest of the file, getting any additional chunks in info_ptr */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600242 png_read_end(png_ptr, info_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500243
244 /* clean up after the read, and free any memory allocated */
Guy Schalnate5a37791996-06-05 15:50:50 -0500245 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500246
247 /* close the file */
248 fclose(fp);
249
250 /* that's it */
251 return;
252}
253
Guy Schalnat6d764711995-12-19 03:22:19 -0600254/* progressively read a file */
255
Guy Schalnat6d764711995-12-19 03:22:19 -0600256int
Guy Schalnate5a37791996-06-05 15:50:50 -0500257initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
Guy Schalnat6d764711995-12-19 03:22:19 -0600258{
Guy Schalnate5a37791996-06-05 15:50:50 -0500259 /* Create and initialize the png_struct with the desired error handler
260 functions. If you want to use the default stderr and longjump method,
261 you can supply NULL for the last three parameters. We also check that
262 the library version is compatible in case we are using dynamically
263 linked libraries.
264 */
265 *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
266 (void *)user_error_ptr, user_error_fn, user_warning_fn);
267
268 if (! *png_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600269 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500270 *info_ptr = NULL;
271 return ERROR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600272 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600273
Guy Schalnate5a37791996-06-05 15:50:50 -0500274 *info_ptr = png_create_info_struct(png_ptr);
275
276 if (! *info_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600277 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500278 png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
279 return ERROR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600280 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600281
Guy Schalnate5a37791996-06-05 15:50:50 -0500282 if (setjmp((*png_ptr)->jmpbuf))
283 {
284 png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
285 return ERROR;
286 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600287
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600288 /* this one's new. You will need to provide all three
289 function callbacks, even if you aren't using them all.
Guy Schalnate5a37791996-06-05 15:50:50 -0500290 These functions shouldn't be dependent on global or
291 static variables if you are decoding several images
292 simultaneously. You should store stream specific data
293 in a separate struct, given as the second parameter,
294 and retrieve the pointer from inside the callbacks using
295 the function png_get_progressive_ptr(png_ptr). */
296 png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600297 info_callback, row_callback, end_callback);
Guy Schalnat6d764711995-12-19 03:22:19 -0600298
Guy Schalnate5a37791996-06-05 15:50:50 -0500299 return OK;
Guy Schalnat6d764711995-12-19 03:22:19 -0600300}
301
302int
Guy Schalnate5a37791996-06-05 15:50:50 -0500303process_data(png_structp *png_ptr, png_infop *info_ptr,
304 png_bytep buffer, png_uint_32 length)
Guy Schalnat6d764711995-12-19 03:22:19 -0600305{
Guy Schalnate5a37791996-06-05 15:50:50 -0500306 if (setjmp((*png_ptr)->jmpbuf))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600307 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500308 /* Free the png_ptr and info_ptr memory on error */
309 png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
310 return ERROR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600311 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600312
Guy Schalnate5a37791996-06-05 15:50:50 -0500313 /* this one's new also. Simply give it chunks of data as
314 they arrive from the data stream (in order, of course).
315 On Segmented machines, don't give it any more than 64K.
316 The library seems to run fine with sizes of 4K, although
317 you can give it much less if necessary (I assume you can
318 give it chunks of 1 byte, but I haven't tried with less
319 than 256 bytes yet). When this function returns, you may
320 want to display any rows that were generated in the row
321 callback, if you aren't already displaying them there. */
322 png_process_data(*png_ptr, *info_ptr, buffer, length);
323 return OK;
Guy Schalnat6d764711995-12-19 03:22:19 -0600324}
325
326info_callback(png_structp png_ptr, png_infop info)
327{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600328/* do any setup here, including setting any of the transformations
329 mentioned in the Reading PNG files section. For now, you _must_
330 call either png_start_read_image() or png_read_update_info()
331 after all the transformations are set (even if you don't set
332 any). You may start getting rows before png_process_data()
333 returns, so this is your last chance to prepare for that. */
Guy Schalnat6d764711995-12-19 03:22:19 -0600334}
335
336row_callback(png_structp png_ptr, png_bytep new_row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600337 png_uint_32 row_num, int pass)
Guy Schalnat6d764711995-12-19 03:22:19 -0600338{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600339/* this function is called for every row in the image. If the
340 image is interlacing, and you turned on the interlace handler,
341 this function will be called for every row in every pass.
342 Some of these rows will not be changed from the previous pass.
343 When the row is not changed, the new_row variable will be NULL.
344 The rows and passes are called in order, so you don't really
345 need the row_num and pass, but I'm supplying them because it
346 may make your life easier.
Guy Schalnat6d764711995-12-19 03:22:19 -0600347
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600348 For the non-NULL rows of interlaced images, you must call
349 png_progressive_combine_row() passing in the row and the
350 old row. You can call this function for NULL rows (it will
351 just return) and for non-interlaced images (it just does the
352 memcpy for you) if it will make the code easier. Thus, you
353 can just do this for all cases: */
Guy Schalnat6d764711995-12-19 03:22:19 -0600354
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600355 png_progressive_combine_row(png_ptr, old_row, new_row);
Guy Schalnat6d764711995-12-19 03:22:19 -0600356
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600357/* where old_row is what was displayed for previous rows. Note
358 that the first pass (pass == 0 really) will completely cover
359 the old row, so the rows do not have to be initialized. After
360 the first pass (and only for interlaced images), you will have
361 to pass the current row, and the function will combine the
362 old row and the new row. */
Guy Schalnat6d764711995-12-19 03:22:19 -0600363}
364
365end_callback(png_structp png_ptr, png_infop info)
366{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600367/* this function is called when the whole image has been read,
368 including any chunks after the image (up to and including
369 the IEND). You will usually have the same info chunk as you
370 had in the header, although some data may have been added
371 to the comments and time fields.
Guy Schalnat6d764711995-12-19 03:22:19 -0600372
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600373 Most people won't do much here, perhaps setting a flag that
374 marks the image as finished. */
Guy Schalnat6d764711995-12-19 03:22:19 -0600375}
376
Guy Schalnat0d580581995-07-20 02:43:20 -0500377/* write a png file */
378void write_png(char *file_name, ... other image information ...)
379{
380 FILE *fp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600381 png_structp png_ptr;
382 png_infop info_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500383
384 /* open the file */
385 fp = fopen(file_name, "wb");
386 if (!fp)
387 return;
388
Guy Schalnate5a37791996-06-05 15:50:50 -0500389 /* Create and initialize the png_struct with the desired error handler
390 functions. If you want to use the default stderr and longjump method,
391 you can supply NULL for the last three parameters. We also check that
392 the library version is compatible in case we are using dynamically
393 linked libraries.
394 */
395 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
396 (void *)user_error_ptr, user_error_fn, user_warning_fn);
397
Guy Schalnat0d580581995-07-20 02:43:20 -0500398 if (!png_ptr)
399 {
400 fclose(fp);
401 return;
402 }
403
Guy Schalnate5a37791996-06-05 15:50:50 -0500404 info_ptr = png_create_info_struct(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500405 if (!info_ptr)
406 {
407 fclose(fp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500408 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500409 return;
410 }
411
412 /* set error handling */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600413 if (setjmp(png_ptr->jmpbuf))
Guy Schalnat0d580581995-07-20 02:43:20 -0500414 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500415 /* If we get here, we had a problem reading the file */
Guy Schalnate5a37791996-06-05 15:50:50 -0500416 fclose(fp);
417 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500418 return;
419 }
420
Guy Schalnat69b14481996-01-10 02:56:49 -0600421 /* set up the output control if you are using standard C streams */
Guy Schalnat0d580581995-07-20 02:43:20 -0500422 png_init_io(png_ptr, fp);
423
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600424 /* set the file information here */
Guy Schalnat0d580581995-07-20 02:43:20 -0500425 info_ptr->width = ;
426 info_ptr->height = ;
427 etc.
428
429 /* set the palette if there is one */
430 info_ptr->valid |= PNG_INFO_PLTE;
431 info_ptr->palette = malloc(256 * sizeof (png_color));
432 info_ptr->num_palette = 256;
433 ... set palette colors ...
434
435 /* optional significant bit chunk */
436 info_ptr->valid |= PNG_INFO_sBIT;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600437 /* if we are dealing with a grayscale image then */
438 info_ptr->sig_bit.gray = true_bit_depth;
439 /* otherwise, if we are dealing with a color image then */
440 info_ptr->sig_bit.red = true_red_bit_depth;
441 info_ptr->sig_bit.green = true_green_bit_depth;
442 info_ptr->sig_bit.blue = true_blue_bit_depth;
443 /* if the image has an alpha channel then */
Guy Schalnat69b14481996-01-10 02:56:49 -0600444 info_ptr->sig_bit.alpha = true_alpha_bit_depth;
445
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600446 /* optional gamma chunk is strongly suggested if you have any guess
447 as to the correct gamma of the image */
448 info_ptr->valid |= PNG_INFO_gAMA;
Guy Schalnat0d580581995-07-20 02:43:20 -0500449 info_ptr->gamma = gamma;
450
Guy Schalnate5a37791996-06-05 15:50:50 -0500451 /* other optional chunks like cHRM, bKGD, tRNS, tEXt, tIME, oFFs, pHYs, */
Guy Schalnat0d580581995-07-20 02:43:20 -0500452
Guy Schalnate5a37791996-06-05 15:50:50 -0500453 /* write the file header information */
Guy Schalnat0d580581995-07-20 02:43:20 -0500454 png_write_info(png_ptr, info_ptr);
455
456 /* set up the transformations you want. Note that these are
457 all optional. Only call them if you want them */
458
459 /* invert monocrome pixels */
460 png_set_invert(png_ptr);
461
462 /* shift the pixels up to a legal bit depth and fill in
463 as appropriate to correctly scale the image */
464 png_set_shift(png_ptr, &(info_ptr->sig_bit));
465
466 /* pack pixels into bytes */
467 png_set_packing(png_ptr);
468
469 /* flip bgr pixels to rgb */
470 png_set_bgr(png_ptr);
471
472 /* swap bytes of 16 bit files to most significant bit first */
473 png_set_swap(png_ptr);
474
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500475 /* get rid of filler bytes, pack rgb into 3 bytes. The
476 filler number is not used. */
477 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
Guy Schalnat0d580581995-07-20 02:43:20 -0500478
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500479 /* turn on interlace handling if you are not using png_write_image() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500480 if (interlacing)
481 number_passes = png_set_interlace_handling(png_ptr);
482 else
483 number_passes = 1;
484
Guy Schalnate5a37791996-06-05 15:50:50 -0500485 /* the easiest way to write the image (you may choose to allocate the
486 memory differently, however) */
487 png_byte row_pointers[height][width];
488
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500489 png_write_image(png_ptr, row_pointers);
490
491 /* the other way to write the image - deal with interlacing */
492
Guy Schalnat0d580581995-07-20 02:43:20 -0500493 for (pass = 0; pass < number_passes; pass++)
494 {
495 /* Write a few rows at a time. */
496 png_write_rows(png_ptr, row_pointers, number_of_rows);
497
498 /* If you are only writing one row at a time, this works */
499 for (y = 0; y < height; y++)
500 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600501 png_bytep row_pointers = row[y];
Guy Schalnat0d580581995-07-20 02:43:20 -0500502 png_write_rows(png_ptr, &row_pointers, 1);
503 }
504 }
505
Guy Schalnate5a37791996-06-05 15:50:50 -0500506 /* You can write optional chunks like tEXt, tIME at the end as well.
507 * Note that if you wrote tEXt or zTXt chunks before the image, and
508 * you aren't writing out more at the end, you have to set
509 * info_ptr->num_text = 0 or they will be written out again.
510 */
511
Guy Schalnat0d580581995-07-20 02:43:20 -0500512 /* write the rest of the file */
513 png_write_end(png_ptr, info_ptr);
514
Guy Schalnat0d580581995-07-20 02:43:20 -0500515 /* if you malloced the palette, free it here */
516 if (info_ptr->palette)
517 free(info_ptr->palette);
518
Guy Schalnate5a37791996-06-05 15:50:50 -0500519 /* if you allocated any text comments, free them here */
520
521 /* clean up after the write, and free any memory allocated */
522 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500523
524 /* close the file */
525 fclose(fp);
526
527 /* that's it */
528 return;
529}
530