diff options
Diffstat (limited to 'example.c')
-rw-r--r-- | example.c | 273 |
1 files changed, 147 insertions, 126 deletions
@@ -2,7 +2,7 @@ #if 0 /* in case someone actually tries to compile this */ /* example.c - an example of using libpng - * Last changed in libpng 1.2.35 [February 14, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * This file has been placed in the public domain by the authors. * Maintained 1998-2009 Glenn Randers-Pehrson * Maintained 1996, 1997 Andreas Dilger) @@ -91,14 +91,15 @@ void read_png(char *file_name) /* We need to open the file */ if ((fp = fopen(file_name, "rb")) == NULL) return (ERROR); + #else no_open_file /* prototype 2 */ -void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ +void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; -#endif no_open_file /* only use one prototype! */ +#endif no_open_file /* Only use one prototype! */ /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, @@ -164,6 +165,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ * pixels) into the info structure with this call: */ png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); + #else /* OK, you're doing it the hard way, with the lower-level functions */ @@ -175,13 +177,13 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); -/* Set up the data transformations you want. Note that these are all - * optional. Only call them if you want/need them. Many of the - * transformations only work on specific types of images, and many - * are mutually exclusive. - */ + /* Set up the data transformations you want. Note that these are all + * optional. Only call them if you want/need them. Many of the + * transformations only work on specific types of images, and many + * are mutually exclusive. + */ - /* tell libpng to strip 16 bit/color files down to 8 bits/color */ + /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* Strip alpha bytes from the input data without combining with the @@ -228,10 +230,11 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - /* Some suggestions as to how to get a screen gamma value */ - - /* Note that screen gamma is the display_exponent, which includes - * the CRT_exponent and any correction for viewing conditions */ + /* Some suggestions as to how to get a screen gamma value + * + * Note that screen gamma is the display_exponent, which includes + * the CRT_exponent and any correction for viewing conditions + */ if (/* We have a user-defined screen gamma value */) { screen_gamma = user-defined screen_gamma; @@ -244,7 +247,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ /* If we don't have another value */ else { - screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly + screen_gamma = 2.2; /* A good guess for a PC monitor in a dimly lit room */ screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ } @@ -277,7 +280,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ png_colorp palette; /* This reduces the image to the application supplied palette */ - if (/* we have our own palette */) + if (/* We have our own palette */) { /* An array of colors to which the image should be dithered */ png_color std_color_cube[MAX_SCREEN_COLORS]; @@ -297,7 +300,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ } } - /* invert monochrome files to have 0 as white and 1 as black */ + /* Invert monochrome files to have 0 as white and 1 as black */ png_set_invert_mono(png_ptr); /* If you want to shift the pixel values from the range [0,255] or @@ -306,20 +309,20 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { - png_color_8p sig_bit; + png_color_8p sig_bit_p; - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - png_set_shift(png_ptr, sig_bit); + png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); + png_set_shift(png_ptr, sig_bit_p); } - /* flip the RGB pixels to BGR (or RGBA to BGRA) */ + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ if (color_type & PNG_COLOR_MASK_COLOR) png_set_bgr(png_ptr); - /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ png_set_swap_alpha(png_ptr); - /* swap bytes of 16 bit files to least significant byte first */ + /* Swap bytes of 16 bit files to least significant byte first */ png_set_swap(png_ptr); /* Add filler (or alpha) byte (before/after each RGB triplet) */ @@ -374,32 +377,31 @@ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ #else no_sparkle /* Read the image using the "rectangle" effect */ png_read_rows(png_ptr, png_bytepp_NULL, &row_pointers[y], number_of_rows); -#endif no_sparkle /* use only one of these two methods */ +#endif no_sparkle /* Use only one of these two methods */ } - /* if you want to display the image after every pass, do - so here */ -#endif no_single /* use only one of these two methods */ + /* If you want to display the image after every pass, do so here */ +#endif no_single /* Use only one of these two methods */ } -#endif no_entire /* use only one of these two methods */ +#endif no_entire /* Use only one of these two methods */ - /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); #endif hilevel /* At this point you have read the entire image */ - /* clean up after the read, and free any memory allocated - REQUIRED */ + /* Clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - /* close the file */ + /* Close the file */ fclose(fp); - /* that's it */ + /* That's it */ return (OK); } -/* progressively read a file */ +/* Progressively read a file */ int initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) @@ -464,7 +466,7 @@ process_data(png_structp *png_ptr, png_infop *info_ptr, /* This one's new also. Simply give it chunks of data as * they arrive from the data stream (in order, of course). - * On Segmented machines, don't give it any more than 64K. + * On segmented machines, don't give it any more than 64K. * The library seems to run fine with sizes of 4K, although * you can give it much less if necessary (I assume you can * give it chunks of 1 byte, but I haven't tried with less @@ -478,34 +480,35 @@ process_data(png_structp *png_ptr, png_infop *info_ptr, info_callback(png_structp png_ptr, png_infop info) { -/* do any setup here, including setting any of the transformations - * mentioned in the Reading PNG files section. For now, you _must_ - * call either png_start_read_image() or png_read_update_info() - * after all the transformations are set (even if you don't set - * any). You may start getting rows before png_process_data() - * returns, so this is your last chance to prepare for that. - */ + /* Do any setup here, including setting any of the transformations + * mentioned in the Reading PNG files section. For now, you _must_ + * call either png_start_read_image() or png_read_update_info() + * after all the transformations are set (even if you don't set + * any). You may start getting rows before png_process_data() + * returns, so this is your last chance to prepare for that. + */ } row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) { -/* - * This function is called for every row in the image. If the - * image is interlaced, and you turned on the interlace handler, - * this function will be called for every row in every pass. - * - * In this function you will receive a pointer to new row data from - * libpng called new_row that is to replace a corresponding row (of - * the same data format) in a buffer allocated by your application. - * - * The new row data pointer new_row may be NULL, indicating there is - * no new data to be replaced (in cases of interlace loading). - * - * If new_row is not NULL then you need to call - * png_progressive_combine_row() to replace the corresponding row as - * shown below: - */ + /* + * This function is called for every row in the image. If the + * image is interlaced, and you turned on the interlace handler, + * this function will be called for every row in every pass. + * + * In this function you will receive a pointer to new row data from + * libpng called new_row that is to replace a corresponding row (of + * the same data format) in a buffer allocated by your application. + * + * The new row data pointer "new_row" may be NULL, indicating there is + * no new data to be replaced (in cases of interlace loading). + * + * If new_row is not NULL then you need to call + * png_progressive_combine_row() to replace the corresponding row as + * shown below: + */ + /* Check if row_num is in bounds. */ if ((row_num >= 0) && (row_num < height)) { @@ -520,44 +523,44 @@ row_callback(png_structp png_ptr, png_bytep new_row, if ((old_row != NULL) && (new_row != NULL)) png_progressive_combine_row(png_ptr, old_row, new_row); } -/* - * The rows and passes are called in order, so you don't really - * need the row_num and pass, but I'm supplying them because it - * may make your life easier. - * - * For the non-NULL rows of interlaced images, you must call - * png_progressive_combine_row() passing in the new row and the - * old row, as demonstrated above. You can call this function for - * NULL rows (it will just return) and for non-interlaced images - * (it just does the png_memcpy for you) if it will make the code - * easier. Thus, you can just do this for all cases: - */ + /* + * The rows and passes are called in order, so you don't really + * need the row_num and pass, but I'm supplying them because it + * may make your life easier. + * + * For the non-NULL rows of interlaced images, you must call + * png_progressive_combine_row() passing in the new row and the + * old row, as demonstrated above. You can call this function for + * NULL rows (it will just return) and for non-interlaced images + * (it just does the png_memcpy for you) if it will make the code + * easier. Thus, you can just do this for all cases: + */ png_progressive_combine_row(png_ptr, old_row, new_row); -/* where old_row is what was displayed for previous rows. Note - * that the first pass (pass == 0 really) will completely cover - * the old row, so the rows do not have to be initialized. After - * the first pass (and only for interlaced images), you will have - * to pass the current row as new_row, and the function will combine - * the old row and the new row. - */ + /* where old_row is what was displayed for previous rows. Note + * that the first pass (pass == 0 really) will completely cover + * the old row, so the rows do not have to be initialized. After + * the first pass (and only for interlaced images), you will have + * to pass the current row as new_row, and the function will combine + * the old row and the new row. + */ } end_callback(png_structp png_ptr, png_infop info) { -/* this function is called when the whole image has been read, - * including any chunks after the image (up to and including - * the IEND). You will usually have the same info chunk as you - * had in the header, although some data may have been added - * to the comments and time fields. - * - * Most people won't do much here, perhaps setting a flag that - * marks the image as finished. - */ + /* This function is called when the whole image has been read, + * including any chunks after the image (up to and including + * the IEND). You will usually have the same info chunk as you + * had in the header, although some data may have been added + * to the comments and time fields. + * + * Most people won't do much here, perhaps setting a flag that + * marks the image as finished. + */ } -/* write a png file */ +/* Write a png file */ void write_png(char *file_name /* , ... other image information ... */) { FILE *fp; @@ -565,7 +568,7 @@ void write_png(char *file_name /* , ... other image information ... */) png_infop info_ptr; png_colorp palette; - /* open the file */ + /* Open the file */ fp = fopen(file_name, "wb"); if (fp == NULL) return (ERROR); @@ -599,30 +602,34 @@ void write_png(char *file_name /* , ... other image information ... */) */ if (setjmp(png_jmpbuf(png_ptr))) { - /* If we get here, we had a problem reading the file */ + /* If we get here, we had a problem writing the file */ fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); return (ERROR); } /* One of the following I/O initialization functions is REQUIRED */ + #ifdef streams /* I/O initialization method 1 */ - /* set up the output control if you are using standard C streams */ + /* Set up the output control if you are using standard C streams */ png_init_io(png_ptr, fp); + #else no_streams /* I/O initialization method 2 */ /* If you are using replacement write functions, instead of calling - * png_init_io() here you would call */ + * png_init_io() here you would call + */ png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, user_IO_flush_function); /* where user_io_ptr is a structure you want available to the callbacks */ -#endif no_streams /* only use one initialization method */ +#endif no_streams /* Only use one initialization method */ #ifdef hilevel /* This is the easy way. Use it if you already have all the - * image info living info in the structure. You could "|" many + * image info living in the structure. You could "|" many * PNG_TRANSFORM flags into the png_transforms integer here. */ png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); + #else /* This is the hard way */ @@ -637,25 +644,27 @@ void write_png(char *file_name /* , ... other image information ... */) png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - /* set the palette if there is one. REQUIRED for indexed-color images */ + /* Set the palette if there is one. REQUIRED for indexed-color images */ palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); - /* ... set palette colors ... */ + /* ... Set palette colors ... */ png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); /* You must not free palette here, because png_set_PLTE only makes a link to - the palette that you malloced. Wait until you are about to destroy - the png structure. */ + * the palette that you malloced. Wait until you are about to destroy + * the png structure. + */ - /* optional significant bit chunk */ - /* if we are dealing with a grayscale image then */ + /* Optional significant bit (sBIT) chunk */ + png_color_8 sig_bit; + /* If we are dealing with a grayscale image then */ sig_bit.gray = true_bit_depth; - /* otherwise, if we are dealing with a color image then */ + /* Otherwise, if we are dealing with a color image then */ sig_bit.red = true_red_bit_depth; sig_bit.green = true_green_bit_depth; sig_bit.blue = true_blue_bit_depth; - /* if the image has an alpha channel then */ + /* If the image has an alpha channel then */ sig_bit.alpha = true_alpha_bit_depth; - png_set_sBIT(png_ptr, info_ptr, sig_bit); + png_set_sBIT(png_ptr, info_ptr, &sig_bit); /* Optional gamma chunk is strongly suggested if you have any guess @@ -680,9 +689,12 @@ void write_png(char *file_name /* , ... other image information ... */) #endif png_set_text(png_ptr, info_ptr, text_ptr, 3); - /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ - /* note that if sRGB is present the gAMA and cHRM chunks must be ignored - * on read and must be written in accordance with the sRGB profile */ + /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */ + + /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored + * on read and, if your application chooses to write them, they must + * be written in accordance with the sRGB profile + */ /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); @@ -694,7 +706,7 @@ void write_png(char *file_name /* , ... other image information ... */) * write_my_chunk(); * png_write_info(png_ptr, info_ptr); * - * However, given the level of known- and unknown-chunk support in 1.1.0 + * However, given the level of known- and unknown-chunk support in 1.2.0 * and up, this should no longer be necessary. */ @@ -704,11 +716,11 @@ void write_png(char *file_name /* , ... other image information ... */) * at the end. */ - /* set up the transformations you want. Note that these are + /* Set up the transformations you want. Note that these are * all optional. Only call them if you want them. */ - /* invert monochrome pixels */ + /* Invert monochrome pixels */ png_set_invert_mono(png_ptr); /* Shift the pixels up to a legal bit depth and fill in @@ -716,10 +728,10 @@ void write_png(char *file_name /* , ... other image information ... */) */ png_set_shift(png_ptr, &sig_bit); - /* pack pixels into bytes */ + /* Pack pixels into bytes */ png_set_packing(png_ptr); - /* swap location of alpha bytes from ARGB to RGBA */ + /* Swap location of alpha bytes from ARGB to RGBA */ png_set_swap_alpha(png_ptr); /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into @@ -727,16 +739,16 @@ void write_png(char *file_name /* , ... other image information ... */) */ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - /* flip BGR pixels to RGB */ + /* Flip BGR pixels to RGB */ png_set_bgr(png_ptr); - /* swap bytes of 16-bit files to most significant byte first */ + /* Swap bytes of 16-bit files to most significant byte first */ png_set_swap(png_ptr); - /* swap bits of 1, 2, 4 bit packed pixel formats */ + /* Swap bits of 1, 2, 4 bit packed pixel formats */ png_set_packswap(png_ptr); - /* turn on interlace handling if you are not using png_write_image() */ + /* Turn on interlace handling if you are not using png_write_image() */ if (interlacing) number_passes = png_set_interlace_handling(png_ptr); else @@ -757,12 +769,14 @@ void write_png(char *file_name /* , ... other image information ... */) row_pointers[k] = image + k*width*bytes_per_pixel; /* One of the following output methods is REQUIRED */ -#ifdef entire /* write out the entire image data in one call */ + +#ifdef entire /* Write out the entire image data in one call */ png_write_image(png_ptr, row_pointers); - /* the other way to write the image - deal with interlacing */ + /* The other way to write the image - deal with interlacing */ + +#else no_entire /* Write out the image data by one or more scanlines */ -#else no_entire /* write out the image data by one or more scanlines */ /* The number of passes is either 1 for non-interlaced images, * or 7 for interlaced images. */ @@ -775,10 +789,10 @@ void write_png(char *file_name /* , ... other image information ... */) for (y = 0; y < height; y++) png_write_rows(png_ptr, &row_pointers[y], 1); } -#endif no_entire /* use only one output method */ +#endif no_entire /* Use only one output method */ /* You can write optional chunks like tEXt, zTXt, and tIME at the end - * as well. Shouldn't be necessary in 1.1.0 and up as all the public + * as well. Shouldn't be necessary in 1.2.0 and up as all the public * chunks are supported and you can use png_set_unknown_chunks() to * register unknown chunks into the info structure to be written out. */ @@ -788,26 +802,33 @@ void write_png(char *file_name /* , ... other image information ... */) #endif hilevel /* If you png_malloced a palette, free it here (don't free info_ptr->palette, - as recommended in versions 1.0.5m and earlier of this example; if - libpng mallocs info_ptr->palette, libpng will free it). If you - allocated it with malloc() instead of png_malloc(), use free() instead - of png_free(). */ + * as recommended in versions 1.0.5m and earlier of this example; if + * libpng mallocs info_ptr->palette, libpng will free it). If you + * allocated it with malloc() instead of png_malloc(), use free() instead + * of png_free(). + */ png_free(png_ptr, palette); palette = NULL; /* Similarly, if you png_malloced any data that you passed in with - png_set_something(), such as a hist or trans array, free it here, - when you can be sure that libpng is through with it. */ + * png_set_something(), such as a hist or trans array, free it here, + * when you can be sure that libpng is through with it. + */ png_free(png_ptr, trans); trans = NULL; + /* Whenever you use png_free() it is a good idea to set the pointer to + * NULL in case your application inadvertently tries to png_free() it + * again. When png_free() sees a NULL it returns without action, thus + * avoiding the double-free security problem. + */ - /* clean up after the write, and free any memory allocated */ + /* Clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); - /* close the file */ + /* Close the file */ fclose(fp); - /* that's it */ + /* That's it */ return (OK); } |