| /* example.c - an example of using libpng */ |
| |
| /* this is an example of how to use libpng to read and write |
| png files. The file libpng.txt is much more verbose then |
| this. If you have not read it, do so first. This was |
| designed to be a starting point of an implementation. |
| This is not officially part of libpng, and therefore |
| does not require a copyright notice. |
| */ |
| |
| #include <png.h> |
| |
| /* check to see if a file is a png file using png_check_sig() */ |
| int check_png(char *file_name) |
| { |
| FILE *fp; |
| char buf[8]; |
| int ret; |
| |
| fp = fopen(file_name, "rb"); |
| if (!fp) |
| return 0; |
| ret = fread(buf, 1, 8, fp); |
| fclose(fp); |
| |
| if (ret != 8) |
| return 0; |
| |
| ret = png_check_sig(buf, 8); |
| |
| return (ret); |
| } |
| |
| /* read a png file. You may want to return an error code if the read |
| fails (depending upon the failure). */ |
| void read_png(char *file_name) |
| { |
| FILE *fp; |
| png_struct *png_ptr; |
| png_info *info_ptr; |
| |
| /* open the file */ |
| fp = fopen(file_name, "rb"); |
| if (!fp) |
| return; |
| |
| /* allocate the necessary structures */ |
| png_ptr = malloc(sizeof (png_struct)); |
| if (!png_ptr) |
| { |
| fclose(fp); |
| return; |
| } |
| |
| info_ptr = malloc(sizeof (png_info)); |
| if (!info_ptr) |
| { |
| fclose(fp); |
| free(png_ptr); |
| return; |
| } |
| |
| /* set error handling */ |
| if (setjmp(png_ptr->jmpbuf)) |
| { |
| png_read_destroy(png_ptr, info_ptr, (png_info *)0); |
| fclose(fp); |
| free(png_ptr); |
| free(info_ptr); |
| /* If we get here, we had a problem reading the file */ |
| return; |
| } |
| |
| /* initialize the structures, info first for error handling */ |
| png_info_init(info_ptr); |
| png_read_init(png_ptr); |
| |
| /* set up the input control */ |
| png_init_io(png_ptr, fp); |
| |
| /* read the file information */ |
| png_read_info(png_ptr, info_ptr); |
| |
| /* allocate the memory to hold the image using the fields |
| of png_info. */ |
| |
| /* set up the transformations you want. Note that these are |
| all optional. Only call them if you want them */ |
| |
| /* expand paletted colors into true rgb */ |
| if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE && |
| info_ptr->bit_depth < 8) |
| png_set_expand(png_ptr); |
| |
| /* expand grayscale images to the full 8 bits */ |
| if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && |
| info_ptr->bit_depth < 8) |
| png_set_expand(png_ptr); |
| |
| /* expand images with transparency to full alpha channels */ |
| if (info_ptr->valid & PNG_INFO_tRNS) |
| png_set_expand(png_ptr); |
| |
| /* Set the background color to draw transparent and alpha |
| images over */ |
| png_color_16 my_background; |
| |
| if (info_ptr->valid & PNG_INFO_bKGD) |
| png_set_background(png_ptr, &(info_ptr->background), |
| PNG_GAMMA_FILE, 1, 1.0); |
| else |
| png_set_background(png_ptr, &my_background, |
| PNG_GAMMA_SCREEN, 0, 1.0); |
| |
| /* tell libpng to handle the gamma conversion for you */ |
| if (info_ptr->valid & PNG_INFO_gAMA) |
| png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma); |
| else |
| png_set_gamma(png_ptr, screen_gamma, 0.45); |
| |
| /* tell libpng to strip 16 bit depth files down to 8 bits */ |
| if (info_ptr->bit_depth == 16) |
| png_set_strip_16(png_ptr); |
| |
| /* dither rgb files down to 8 bit palettes & reduce palettes |
| to the number of colors available on your screen */ |
| if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) |
| { |
| if (info_ptr->valid & PNG_INFO_PLTE) |
| png_set_dither(png_ptr, info_ptr->palette, |
| info_ptr->num_palette, max_screen_colors, |
| info_ptr->histogram); |
| else |
| { |
| png_color std_color_cube[MAX_SCREEN_COLORS] = |
| {/* ... colors ... */}; |
| |
| png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, |
| MAX_SCREEN_COLORS, NULL); |
| } |
| } |
| |
| /* invert monocrome files */ |
| if (info_ptr->bit_depth == 1 && |
| info_ptr->color_type == PNG_COLOR_GRAY) |
| png_set_invert(png_ptr); |
| |
| /* shift the pixels down to their true bit depth */ |
| if (info_ptr->valid & PNG_INFO_sBIT && |
| info_ptr->bit_depth > info_ptr->sig_bit) |
| png_set_shift(png_ptr, &(info_ptr->sig_bit)); |
| |
| /* pack pixels into bytes */ |
| if (info_ptr->bit_depth < 8) |
| png_set_packing(png_ptr); |
| |
| /* flip the rgb pixels to bgr */ |
| if (info_ptr->color_type == PNG_COLOR_TYPE_RGB || |
| info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) |
| png_set_bgr(png_ptr); |
| |
| /* swap bytes of 16 bit files to least significant bit first */ |
| if (info_ptr->bit_depth == 16) |
| png_set_swap(png_ptr); |
| |
| /* add a filler byte to store rgb files as rgbx */ |
| if (info_ptr->bit_depth == 8 && |
| info_ptr->color_type == PNG_COLOR_TYPE_RGB) |
| png_set_rgbx(png_ptr); |
| |
| /* optional call to update palette with transformations */ |
| png_start_read_image(png_ptr); |
| |
| /* the easiest way to read the image */ |
| void *row_pointers[height]; |
| png_read_image(png_ptr, row_pointers); |
| |
| /* the other way to read images - deal with interlacing */ |
| |
| /* turn on interlace handling */ |
| if (info_ptr->interlace_type) |
| number_passes = png_set_interlace_handling(png_ptr); |
| else |
| number_passes = 1; |
| |
| for (pass = 0; pass < number_passes; pass++) |
| { |
| /* Read the image using the "sparkle" effect. */ |
| png_read_rows(png_ptr, row_pointers, NULL, number_of_rows); |
| |
| /* If you are only reading on row at a time, this works */ |
| for (y = 0; y < height; y++) |
| { |
| char *row_pointers = row[y]; |
| png_read_rows(png_ptr, &row_pointers, NULL, 1); |
| } |
| |
| /* to get the rectangle effect, use the third parameter */ |
| png_read_rows(png_ptr, NULL, row_pointers, number_of_rows); |
| |
| /* if you want to display the image after every pass, do |
| so here */ |
| } |
| |
| /* read the rest of the file, getting any additional chunks |
| in info_ptr */ |
| png_read_end(png_ptr, info_ptr); |
| |
| /* clean up after the read, and free any memory allocated */ |
| png_read_destroy(png_ptr, info_ptr, (png_info *)0); |
| |
| /* free the structures */ |
| free(png_ptr); |
| free(info_ptr); |
| |
| /* close the file */ |
| fclose(fp); |
| |
| /* that's it */ |
| return; |
| } |
| |
| /* write a png file */ |
| void write_png(char *file_name, ... other image information ...) |
| { |
| FILE *fp; |
| png_struct *png_ptr; |
| png_info *info_ptr; |
| |
| /* open the file */ |
| fp = fopen(file_name, "wb"); |
| if (!fp) |
| return; |
| |
| /* allocate the necessary structures */ |
| png_ptr = malloc(sizeof (png_struct)); |
| if (!png_ptr) |
| { |
| fclose(fp); |
| return; |
| } |
| |
| info_ptr = malloc(sizeof (png_info)); |
| if (!info_ptr) |
| { |
| fclose(fp); |
| free(png_ptr); |
| return; |
| } |
| |
| /* set error handling */ |
| if (setjmp(png_ptr->jmpbuf)) |
| { |
| png_write_destroy(png_ptr); |
| fclose(fp); |
| free(png_ptr); |
| free(info_ptr); |
| /* If we get here, we had a problem reading the file */ |
| return; |
| } |
| |
| /* initialize the structures */ |
| png_info_init(info_ptr); |
| png_write_init(png_ptr); |
| |
| /* set up the output control */ |
| png_init_io(png_ptr, fp); |
| |
| /* set the file information here */ |
| info_ptr->width = ; |
| info_ptr->height = ; |
| etc. |
| |
| /* set the palette if there is one */ |
| info_ptr->valid |= PNG_INFO_PLTE; |
| info_ptr->palette = malloc(256 * sizeof (png_color)); |
| info_ptr->num_palette = 256; |
| ... set palette colors ... |
| |
| /* optional significant bit chunk */ |
| info_ptr->valid |= PNG_INFO_sBIT; |
| info_ptr->sig_bit = true_bit_depth; |
| |
| /* optional gamma chunk */ |
| info_ptr->valid |= PNG_INFO_gAMA; |
| info_ptr->gamma = gamma; |
| |
| /* other optional chunks */ |
| |
| /* write the file information */ |
| png_write_info(png_ptr, info_ptr); |
| |
| /* set up the transformations you want. Note that these are |
| all optional. Only call them if you want them */ |
| |
| /* invert monocrome pixels */ |
| png_set_invert(png_ptr); |
| |
| /* shift the pixels up to a legal bit depth and fill in |
| as appropriate to correctly scale the image */ |
| png_set_shift(png_ptr, &(info_ptr->sig_bit)); |
| |
| /* pack pixels into bytes */ |
| png_set_packing(png_ptr); |
| |
| /* flip bgr pixels to rgb */ |
| png_set_bgr(png_ptr); |
| |
| /* swap bytes of 16 bit files to most significant bit first */ |
| png_set_swap(png_ptr); |
| |
| /* get rid of filler bytes, pack rgb into 3 bytes */ |
| png_set_rgbx(png_ptr); |
| |
| /* the easiest way to write the image */ |
| void *row_pointers[height]; |
| png_write_image(png_ptr, row_pointers); |
| |
| /* the other way to write the image - deal with interlacing */ |
| |
| /* turn on interlace handling */ |
| if (interlacing) |
| number_passes = png_set_interlace_handling(png_ptr); |
| else |
| number_passes = 1; |
| |
| for (pass = 0; pass < number_passes; pass++) |
| { |
| /* Write a few rows at a time. */ |
| png_write_rows(png_ptr, row_pointers, number_of_rows); |
| |
| /* If you are only writing one row at a time, this works */ |
| for (y = 0; y < height; y++) |
| { |
| char *row_pointers = row[y]; |
| png_write_rows(png_ptr, &row_pointers, 1); |
| } |
| } |
| |
| /* write the rest of the file */ |
| png_write_end(png_ptr, info_ptr); |
| |
| /* clean up after the write, and free any memory allocated */ |
| png_write_destroy(png_ptr); |
| |
| /* if you malloced the palette, free it here */ |
| if (info_ptr->palette) |
| free(info_ptr->palette); |
| |
| /* free the structures */ |
| free(png_ptr); |
| free(info_ptr); |
| |
| /* close the file */ |
| fclose(fp); |
| |
| /* that's it */ |
| return; |
| } |
| |