blob: 63d7962e707a8824884e9a2049c8a332025661c1 [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
51 /* allocate the necessary structures */
52 png_ptr = malloc(sizeof (png_struct));
53 if (!png_ptr)
54 {
55 fclose(fp);
56 return;
57 }
58
59 info_ptr = malloc(sizeof (png_info));
60 if (!info_ptr)
61 {
62 fclose(fp);
63 free(png_ptr);
64 return;
65 }
66
67 /* set error handling */
68 if (setjmp(png_ptr->jmpbuf))
69 {
70 png_read_destroy(png_ptr, info_ptr, (png_info *)0);
71 fclose(fp);
72 free(png_ptr);
73 free(info_ptr);
74 /* If we get here, we had a problem reading the file */
75 return;
76 }
77
78 /* initialize the structures, info first for error handling */
79 png_info_init(info_ptr);
80 png_read_init(png_ptr);
81
Guy Schalnat69b14481996-01-10 02:56:49 -060082 /* set up the input control if you are using standard C streams */
Guy Schalnat0d580581995-07-20 02:43:20 -050083 png_init_io(png_ptr, fp);
84
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060085 /* if you are using replacement read functions, here you would call */
86 png_set_read_fn(png_ptr, (void *)io_ptr, user_read_fn);
87 /* where io_ptr is a structure you want available to the callbacks */
Guy Schalnat0d580581995-07-20 02:43:20 -050088
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060089 /* if you are using replacement message functions, here you would call */
90 png_set_message_fn(png_ptr, (void *)msg_ptr, user_error_fn, user_warning_fn);
91 /* where msg_ptr is a structure you want available to the callbacks */
Guy Schalnat69b14481996-01-10 02:56:49 -060092
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060093 /* read the file information */
94 png_read_info(png_ptr, info_ptr);
Guy Schalnat69b14481996-01-10 02:56:49 -060095
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060096 /* set up the transformations you want. Note that these are
Guy Schalnat0d580581995-07-20 02:43:20 -050097 all optional. Only call them if you want them */
98
99 /* expand paletted colors into true rgb */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500100 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500101 png_set_expand(png_ptr);
102
103 /* expand grayscale images to the full 8 bits */
104 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
105 info_ptr->bit_depth < 8)
106 png_set_expand(png_ptr);
107
108 /* expand images with transparency to full alpha channels */
109 if (info_ptr->valid & PNG_INFO_tRNS)
110 png_set_expand(png_ptr);
111
112 /* Set the background color to draw transparent and alpha
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600113 images over */
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 Schalnatb2e01bd1996-01-26 01:38:47 -0600118 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
119 else
120 png_set_background(png_ptr, &my_background,
Guy Schalnat6d764711995-12-19 03:22:19 -0600121 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
129 /* tell libpng to strip 16 bit depth files down to 8 bits */
130 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
133 /* dither rgb files down to 8 bit palettes & reduce palettes
134 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)
138 png_set_dither(png_ptr, info_ptr->palette,
139 info_ptr->num_palette, max_screen_colors,
140 info_ptr->histogram);
141 else
142 {
143 png_color std_color_cube[MAX_SCREEN_COLORS] =
144 {/* ... colors ... */};
145
146 png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
147 MAX_SCREEN_COLORS, NULL);
148 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600149 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500150
151 /* invert monocrome files */
152 if (info_ptr->bit_depth == 1 &&
153 info_ptr->color_type == PNG_COLOR_GRAY)
154 png_set_invert(png_ptr);
155
156 /* shift the pixels down to their true bit depth */
Guy Schalnat6d764711995-12-19 03:22:19 -0600157 if (info_ptr->valid & PNG_INFO_sBIT &&
158 info_ptr->bit_depth > info_ptr->sig_bit)
Guy Schalnat0d580581995-07-20 02:43:20 -0500159 png_set_shift(png_ptr, &(info_ptr->sig_bit));
160
161 /* pack pixels into bytes */
162 if (info_ptr->bit_depth < 8)
163 png_set_packing(png_ptr);
164
165 /* flip the rgb pixels to bgr */
166 if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600167 info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -0500168 png_set_bgr(png_ptr);
169
170 /* swap bytes of 16 bit files to least significant bit first */
171 if (info_ptr->bit_depth == 16)
172 png_set_swap(png_ptr);
173
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500174 /* add a filler byte to rgb files */
Guy Schalnat0d580581995-07-20 02:43:20 -0500175 if (info_ptr->bit_depth == 8 &&
176 info_ptr->color_type == PNG_COLOR_TYPE_RGB)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500177 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
Guy Schalnat0d580581995-07-20 02:43:20 -0500178
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500179 /* turn on interlace handling if you are not using png_read_image() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500180 if (info_ptr->interlace_type)
181 number_passes = png_set_interlace_handling(png_ptr);
182 else
183 number_passes = 1;
184
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600185 /* optional call to update palette with transformations */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500186 png_start_read_image(png_ptr);
187
188 /* optional call to update the info structure */
189 png_read_update_info(png_ptr, info_ptr);
190
191 /* allocate the memory to hold the image using the fields
192 of png_info. */
193
194 /* the easiest way to read the image */
Guy Schalnat6d764711995-12-19 03:22:19 -0600195 png_bytep row_pointers[height];
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500196 png_read_image(png_ptr, row_pointers);
197
198 /* the other way to read images - deal with interlacing */
199
Guy Schalnat0d580581995-07-20 02:43:20 -0500200 for (pass = 0; pass < number_passes; pass++)
201 {
202 /* Read the image using the "sparkle" effect. */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600203 png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);
Guy Schalnat0d580581995-07-20 02:43:20 -0500204
205 /* If you are only reading on row at a time, this works */
206 for (y = 0; y < height; y++)
207 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600208 png_bytep row_pointers = row[y];
Guy Schalnat0d580581995-07-20 02:43:20 -0500209 png_read_rows(png_ptr, &row_pointers, NULL, 1);
210 }
211
212 /* to get the rectangle effect, use the third parameter */
213 png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);
214
215 /* if you want to display the image after every pass, do
216 so here */
217 }
218
219 /* read the rest of the file, getting any additional chunks
220 in info_ptr */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600221 png_read_end(png_ptr, info_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500222
223 /* clean up after the read, and free any memory allocated */
Guy Schalnat6d764711995-12-19 03:22:19 -0600224 png_read_destroy(png_ptr, info_ptr, (png_infop)0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500225
226 /* free the structures */
227 free(png_ptr);
228 free(info_ptr);
229
230 /* close the file */
231 fclose(fp);
232
233 /* that's it */
234 return;
235}
236
Guy Schalnat6d764711995-12-19 03:22:19 -0600237/* progressively read a file */
238
239/* these will normally not be global unless you are only
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600240 reading in one image at a time */
Guy Schalnat6d764711995-12-19 03:22:19 -0600241png_structp png_ptr;
242png_infop info_ptr;
243
244int
245initialize_png_reader()
246{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600247 png_ptr = malloc(sizeof (png_struct));
248 if (!png_ptr)
249 return -1;
250 info_ptr = malloc(sizeof (png_info));
251 if (!info_ptr)
252 {
253 free(png_ptr);
254 return -1;
255 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600256
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600257 if (setjmp(png_ptr->jmpbuf))
258 {
259 png_read_destroy(png_ptr, info_ptr, (png_info *)0);
260 /* free pointers before returning, if necessary */
261 free(png_ptr);
262 free(info_ptr);
263 return -1;
264 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600265
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600266 png_info_init(info_ptr);
267 png_read_init(png_ptr);
Guy Schalnat6d764711995-12-19 03:22:19 -0600268
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600269 /* this one's new. You will need to provide all three
270 function callbacks, even if you aren't using them all.
271 You can put a void pointer in place of the NULL, and
272 retrieve the pointer from inside the callbacks using
273 the function png_get_progressive_ptr(png_ptr); */
274 png_set_progressive_read_fn(png_ptr, NULL,
275 info_callback, row_callback, end_callback);
Guy Schalnat6d764711995-12-19 03:22:19 -0600276
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600277 return 0;
Guy Schalnat6d764711995-12-19 03:22:19 -0600278}
279
280int
281process_data(png_bytep buffer, png_uint_32 length)
282{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600283 if (setjmp(png_ptr->jmpbuf))
284 {
285 png_read_destroy(png_ptr, info_ptr, (png_info *)0);
286 free(png_ptr);
287 free(info_ptr);
288 return -1;
289 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600290
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600291 /* this one's new also. Simply give it a chunk of data
292 from the file stream (in order, of course). On Segmented
293 machines, don't give it any more then 64K. The library
294 seems to run fine with sizes of 4K, although you can give
295 it much less if necessary (I assume you can give it chunks
296 of 1 byte, but I haven't tried less then 256 bytes yet).
297 When this function returns, you may want to display any
298 rows that were generated in the row callback. */
299 png_process_data(png_ptr, info_ptr, buffer, length);
300 return 0;
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
366 /* allocate the necessary structures */
367 png_ptr = malloc(sizeof (png_struct));
368 if (!png_ptr)
369 {
370 fclose(fp);
371 return;
372 }
373
374 info_ptr = malloc(sizeof (png_info));
375 if (!info_ptr)
376 {
377 fclose(fp);
378 free(png_ptr);
379 return;
380 }
381
382 /* set error handling */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600383 if (setjmp(png_ptr->jmpbuf))
Guy Schalnat0d580581995-07-20 02:43:20 -0500384 {
385 png_write_destroy(png_ptr);
386 fclose(fp);
387 free(png_ptr);
388 free(info_ptr);
389 /* If we get here, we had a problem reading the file */
390 return;
391 }
392
393 /* initialize the structures */
394 png_info_init(info_ptr);
395 png_write_init(png_ptr);
396
Guy Schalnat69b14481996-01-10 02:56:49 -0600397 /* set up the output control if you are using standard C streams */
Guy Schalnat0d580581995-07-20 02:43:20 -0500398 png_init_io(png_ptr, fp);
399
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600400 /* if you are using replacement write functions, here you would call */
401 png_set_write_fn(png_ptr, (void *)io_ptr, user_write_fn, user_flush_fn);
402 /* where io_ptr is a structure you want available to the callbacks */
Guy Schalnat69b14481996-01-10 02:56:49 -0600403
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600404 /* if you are using replacement message functions, here you would call */
405 png_set_message_fn(png_ptr, (void *)msg_ptr, user_error_fn, user_warning_fn);
406 /* where msg_ptr is a structure you want available to the callbacks */
Guy Schalnat69b14481996-01-10 02:56:49 -0600407
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600408 /* set the file information here */
Guy Schalnat0d580581995-07-20 02:43:20 -0500409 info_ptr->width = ;
410 info_ptr->height = ;
411 etc.
412
413 /* set the palette if there is one */
414 info_ptr->valid |= PNG_INFO_PLTE;
415 info_ptr->palette = malloc(256 * sizeof (png_color));
416 info_ptr->num_palette = 256;
417 ... set palette colors ...
418
419 /* optional significant bit chunk */
420 info_ptr->valid |= PNG_INFO_sBIT;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600421 /* if we are dealing with a grayscale image then */
422 info_ptr->sig_bit.gray = true_bit_depth;
423 /* otherwise, if we are dealing with a color image then */
424 info_ptr->sig_bit.red = true_red_bit_depth;
425 info_ptr->sig_bit.green = true_green_bit_depth;
426 info_ptr->sig_bit.blue = true_blue_bit_depth;
427 /* if the image has an alpha channel then */
Guy Schalnat69b14481996-01-10 02:56:49 -0600428 info_ptr->sig_bit.alpha = true_alpha_bit_depth;
429
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600430 /* optional gamma chunk is strongly suggested if you have any guess
431 as to the correct gamma of the image */
432 info_ptr->valid |= PNG_INFO_gAMA;
Guy Schalnat0d580581995-07-20 02:43:20 -0500433 info_ptr->gamma = gamma;
434
435 /* other optional chunks */
436
437 /* write the file information */
438 png_write_info(png_ptr, info_ptr);
439
440 /* set up the transformations you want. Note that these are
441 all optional. Only call them if you want them */
442
443 /* invert monocrome pixels */
444 png_set_invert(png_ptr);
445
446 /* shift the pixels up to a legal bit depth and fill in
447 as appropriate to correctly scale the image */
448 png_set_shift(png_ptr, &(info_ptr->sig_bit));
449
450 /* pack pixels into bytes */
451 png_set_packing(png_ptr);
452
453 /* flip bgr pixels to rgb */
454 png_set_bgr(png_ptr);
455
456 /* swap bytes of 16 bit files to most significant bit first */
457 png_set_swap(png_ptr);
458
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500459 /* get rid of filler bytes, pack rgb into 3 bytes. The
460 filler number is not used. */
461 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
Guy Schalnat0d580581995-07-20 02:43:20 -0500462
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500463 /* turn on interlace handling if you are not using png_write_image() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500464 if (interlacing)
465 number_passes = png_set_interlace_handling(png_ptr);
466 else
467 number_passes = 1;
468
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500469 /* the easiest way to write the image */
Guy Schalnat6d764711995-12-19 03:22:19 -0600470 png_bytep row_pointers[height];
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500471 png_write_image(png_ptr, row_pointers);
472
473 /* the other way to write the image - deal with interlacing */
474
Guy Schalnat0d580581995-07-20 02:43:20 -0500475 for (pass = 0; pass < number_passes; pass++)
476 {
477 /* Write a few rows at a time. */
478 png_write_rows(png_ptr, row_pointers, number_of_rows);
479
480 /* If you are only writing one row at a time, this works */
481 for (y = 0; y < height; y++)
482 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600483 png_bytep row_pointers = row[y];
Guy Schalnat0d580581995-07-20 02:43:20 -0500484 png_write_rows(png_ptr, &row_pointers, 1);
485 }
486 }
487
488 /* write the rest of the file */
489 png_write_end(png_ptr, info_ptr);
490
Guy Schalnat0d580581995-07-20 02:43:20 -0500491 /* clean up after the write, and free any memory allocated */
492 png_write_destroy(png_ptr);
493
494 /* if you malloced the palette, free it here */
495 if (info_ptr->palette)
496 free(info_ptr->palette);
497
498 /* free the structures */
499 free(png_ptr);
500 free(info_ptr);
501
502 /* close the file */
503 fclose(fp);
504
505 /* that's it */
506 return;
507}
508