libpng/example.c

404 lines
12 KiB
C
Raw Normal View History

1995-07-20 03:43:20 -04:00
/* 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.
1995-09-26 06:22:39 -04:00
This file does not currently compile, because it is missing
certain parts, like allocating memory to hold an image.
You will have to supply these parts to get it to compile.
1995-07-20 03:43:20 -04:00
*/
#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);
1995-11-28 12:22:13 -05:00
/* set up the input control for the default input and message functions.
* If we were to replace both the input and message functions we don't
* need to call png_init_io first. */
1995-07-20 03:43:20 -04:00
png_init_io(png_ptr, fp);
1995-11-28 12:22:13 -05:00
/* if you are using replacement read functions, here you would call */
io_ptr = (user_io_struct *)malloc(sizeof(user_io_struct));
png_set_read_fn(png_ptr, (void *)io_ptr, user_read_fn);
/* if you are using replacement message functions, here you would call */
msg_ptr = (user_msg_struct *)malloc(sizeof(user_msg_struct));
png_set_read_fn(png_ptr, (void *)msg_ptr, user_error_fn, user_warning_fn);
1995-07-20 03:43:20 -04:00
/* read the file information */
png_read_info(png_ptr, info_ptr);
/* 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 */
1995-09-26 06:22:39 -04:00
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1995-07-20 03:43:20 -04:00
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 */
1995-11-28 12:22:13 -05:00
if (info_ptr->valid & PNG_INFO_sBIT)
1995-07-20 03:43:20 -04:00
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);
1995-09-26 06:22:39 -04:00
/* add a filler byte to rgb files */
1995-07-20 03:43:20 -04:00
if (info_ptr->bit_depth == 8 &&
info_ptr->color_type == PNG_COLOR_TYPE_RGB)
1995-09-26 06:22:39 -04:00
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
/* turn on interlace handling if you are not using png_read_image() */
if (info_ptr->interlace_type)
number_passes = png_set_interlace_handling(png_ptr);
else
number_passes = 1;
1995-07-20 03:43:20 -04:00
/* optional call to update palette with transformations */
png_start_read_image(png_ptr);
1995-09-26 06:22:39 -04:00
/* optional call to update the info structure */
png_read_update_info(png_ptr, info_ptr);
/* allocate the memory to hold the image using the fields
of png_info. */
1995-07-20 03:43:20 -04:00
/* the easiest way to read the image */
1995-09-26 06:22:39 -04:00
png_bytef *row_pointers[height];
1995-07-20 03:43:20 -04:00
png_read_image(png_ptr, row_pointers);
/* the other way to read images - deal with interlacing */
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++)
{
1995-09-26 06:22:39 -04:00
png_bytef *row_pointers = row[y];
1995-07-20 03:43:20 -04:00
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);
1995-11-28 12:22:13 -05:00
/* if you had allocated any memory structures for custom input or
messaging routines you need to free them before png_read_destroy */
free(png_get_io_ptr(png_ptr));
free(png_get_msg_ptr(png_ptr));
1995-07-20 03:43:20 -04:00
/* 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);
1995-11-28 12:22:13 -05:00
/* set up the output control for the default output and message functions.
* If we were to replace both the output and message functions we don't
* need to call png_init_io first. */
1995-07-20 03:43:20 -04:00
png_init_io(png_ptr, fp);
1995-11-28 12:22:13 -05:00
/* if you are using replacement write functions, here you would call */
io_ptr = (user_io_struct *)malloc(sizeof(user_io_struct));
png_set_write_fn(png_ptr, (void *)io_ptr, user_write_fn, user_flush_fn);
/* if you are using replacement message functions, here you would call */
msg_ptr = (user_msg_struct *)malloc(sizeof(user_msg_struct));
png_set_read_fn(png_ptr, (void *)msg_ptr, user_error_fn, user_warning_fn);
1995-07-20 03:43:20 -04:00
/* 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;
1995-11-28 12:22:13 -05:00
/* if we are dealing with a grayscale image then */
info_ptr->sig_bit.gray = true_bit_depth;
/* otherwise, if we are dealing with a color image then */
info_ptr->sig_bit.red = true_red_bit_depth;
info_ptr->sig_bit.green = true_green_bit_depth;
info_ptr->sig_bit.blue = true_blue_bit_depth;
/* if the image has an alpha channel then */
info_ptr->sig_bit.alpha = true_alpha_bit_depth;
/* optional gamma chunk is a good idea if you can write one */
1995-07-20 03:43:20 -04:00
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);
1995-09-26 06:22:39 -04:00
/* get rid of filler bytes, pack rgb into 3 bytes. The
filler number is not used. */
png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
1995-07-20 03:43:20 -04:00
1995-09-26 06:22:39 -04:00
/* turn on interlace handling if you are not using png_write_image() */
1995-07-20 03:43:20 -04:00
if (interlacing)
number_passes = png_set_interlace_handling(png_ptr);
else
number_passes = 1;
1995-09-26 06:22:39 -04:00
/* the easiest way to write the image */
png_bytef *row_pointers[height];
png_write_image(png_ptr, row_pointers);
/* the other way to write the image - deal with interlacing */
1995-07-20 03:43:20 -04:00
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++)
{
1995-09-26 06:22:39 -04:00
png_bytef *row_pointers = row[y];
1995-07-20 03:43:20 -04:00
png_write_rows(png_ptr, &row_pointers, 1);
}
}
/* write the rest of the file */
png_write_end(png_ptr, info_ptr);
1995-11-28 12:22:13 -05:00
/* if you had allocated any memory structures for custom output or
messaging routines you need to free them before png_write_destroy */
free(png_get_io_ptr(png_ptr));
free(png_get_msg_ptr(png_ptr));
1995-07-20 03:43:20 -04:00
/* 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;
}