📄 pngwutil.c
字号:
/* pngwutil.c - utilities to write a png file
libpng 1.0 beta 3 - version 0.89
For conditions of distribution and use, see copyright notice in png.h
Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
May 25, 1996
*/
#define PNG_INTERNAL
#include "png.h"
/* place a 32 bit number into a buffer in png byte order. We work
with unsigned numbers for convenience, you may have to cast
signed numbers (if you use any, most png data is unsigned). */
void
png_save_uint_32(png_bytep buf, png_uint_32 i)
{
buf[0] = (png_byte)((i >> 24) & 0xff);
buf[1] = (png_byte)((i >> 16) & 0xff);
buf[2] = (png_byte)((i >> 8) & 0xff);
buf[3] = (png_byte)(i & 0xff);
}
/* place a 16 bit number into a buffer in png byte order */
void
png_save_uint_16(png_bytep buf, png_uint_16 i)
{
buf[0] = (png_byte)((i >> 8) & 0xff);
buf[1] = (png_byte)(i & 0xff);
}
/* write a 32 bit number */
void
png_write_uint_32(png_structp png_ptr, png_uint_32 i)
{
png_byte buf[4];
buf[0] = (png_byte)((i >> 24) & 0xff);
buf[1] = (png_byte)((i >> 16) & 0xff);
buf[2] = (png_byte)((i >> 8) & 0xff);
buf[3] = (png_byte)(i & 0xff);
png_write_data(png_ptr, buf, 4);
}
/* write a 16 bit number */
void
png_write_uint_16(png_structp png_ptr, png_uint_16 i)
{
png_byte buf[2];
buf[0] = (png_byte)((i >> 8) & 0xff);
buf[1] = (png_byte)(i & 0xff);
png_write_data(png_ptr, buf, 2);
}
/* Write a png chunk all at once. The type is an array of ASCII characters
representing the chunk name. The array must be at least 4 bytes in
length, and does not need to be null terminated. To be safe, pass the
pre-defined chunk names here, and if you need a new one, define it
where the others are defined. The length is the length of the data.
All the data must be present. If that is not possible, use the
png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
functions instead. */
void
png_write_chunk(png_structp png_ptr, png_bytep type,
png_bytep data, png_uint_32 length)
{
/* write length */
png_write_uint_32(png_ptr, length);
/* write chunk name */
png_write_data(png_ptr, type, (png_uint_32)4);
/* reset the crc and run the chunk name over it */
png_reset_crc(png_ptr);
png_calculate_crc(png_ptr, type, (png_uint_32)4);
/* write the data and update the crc */
if (length)
{
png_calculate_crc(png_ptr, data, length);
png_write_data(png_ptr, data, length);
}
/* write the crc */
png_write_uint_32(png_ptr, ~png_ptr->crc);
}
/* Write the start of a png chunk. The type is the chunk type.
The total_length is the sum of the lengths of all the data you will be
passing in png_write_chunk_data() */
void
png_write_chunk_start(png_structp png_ptr, png_bytep type,
png_uint_32 total_length)
{
/* write the length */
png_write_uint_32(png_ptr, total_length);
/* write the chunk name */
png_write_data(png_ptr, type, (png_uint_32)4);
/* reset the crc and run it over the chunk name */
png_reset_crc(png_ptr);
png_calculate_crc(png_ptr, type, (png_uint_32)4);
}
/* write the data of a png chunk started with png_write_chunk_start().
Note that multiple calls to this function are allowed, and that the
sum of the lengths from these calls *must* add up to the total_length
given to png_write_chunk_start() */
void
png_write_chunk_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
{
/* write the data, and run the crc over it */
if (length)
{
png_calculate_crc(png_ptr, data, length);
png_write_data(png_ptr, data, length);
}
}
/* finish a chunk started with png_write_chunk_start() */
void
png_write_chunk_end(png_structp png_ptr)
{
/* write the crc */
png_write_uint_32(png_ptr, ~png_ptr->crc);
}
/* simple function to write the signature */
void
png_write_sig(png_structp png_ptr)
{
/* write the 8 byte signature */
png_write_data(png_ptr, png_sig, (png_uint_32)8);
}
/* Write the IHDR chunk, and update the png_struct with the necessary
information. Note that the rest of this code depends upon this
information being correct. */
void
png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
int bit_depth, int color_type, int compression_type, int filter_type,
int interlace_type)
{
png_byte buf[13]; /* buffer to store the IHDR info */
/* Check that we have valid input data from the application info */
switch (color_type)
{
case 0:
switch (bit_depth)
{
case 1:
case 2:
case 4:
case 8:
case 16: png_ptr->channels = 1; break;
default: png_error(png_ptr, "Invalid bit depth for grayscale image");
}
break;
case 2:
if (bit_depth != 8 && bit_depth != 16)
png_error(png_ptr, "Invalid bit depth for RGB image");
png_ptr->channels = 3;
break;
case 3:
switch (bit_depth)
{
case 1:
case 2:
case 4:
case 8: png_ptr->channels = 1; break;
default: png_error(png_ptr, "Invalid bit depth for paletted image");
}
break;
case 4:
if (bit_depth != 8 && bit_depth != 16)
png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
png_ptr->channels = 2;
break;
case 6:
if (bit_depth != 8 && bit_depth != 16)
png_error(png_ptr, "Invalid bit depth for RGBA image");
png_ptr->channels = 4;
break;
default:
png_error(png_ptr, "Invalid image color type specified");
}
if (compression_type != 0)
{
png_warning(png_ptr, "Invalid compression type specified");
compression_type = 0;
}
if (filter_type != 0)
{
png_warning(png_ptr, "Invalid filter type specified");
filter_type = 0;
}
if (interlace_type != 0 && interlace_type != 1)
{
png_warning(png_ptr, "Invalid interlace type specified");
interlace_type = 1;
}
/* save off the relevent information */
png_ptr->bit_depth = (png_byte)bit_depth;
png_ptr->color_type = (png_byte)color_type;
png_ptr->interlaced = (png_byte)interlace_type;
png_ptr->width = width;
png_ptr->height = height;
png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
png_ptr->rowbytes = ((width * (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
/* set the usr info, so any transformations can modify it */
png_ptr->usr_width = png_ptr->width;
png_ptr->usr_bit_depth = png_ptr->bit_depth;
png_ptr->usr_channels = png_ptr->channels;
/* pack the header information into the buffer */
png_save_uint_32(buf, width);
png_save_uint_32(buf + 4, height);
buf[8] = (png_byte)bit_depth;
buf[9] = (png_byte)color_type;
buf[10] = (png_byte)compression_type;
buf[11] = (png_byte)filter_type;
buf[12] = (png_byte)interlace_type;
/* write the chunk */
png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13);
/* initialize zlib with png info */
png_ptr->zstream = (z_stream *)png_malloc(png_ptr, sizeof (z_stream));
png_ptr->zstream->zalloc = png_zalloc;
png_ptr->zstream->zfree = png_zfree;
png_ptr->zstream->opaque = (voidpf)png_ptr;
if (!(png_ptr->do_filter))
{
if (png_ptr->color_type == 3 || png_ptr->bit_depth < 8)
png_ptr->do_filter = PNG_FILTER_NONE;
else
png_ptr->do_filter = PNG_ALL_FILTERS;
}
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
{
if (png_ptr->do_filter != PNG_FILTER_NONE)
png_ptr->zlib_strategy = Z_FILTERED;
else
png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
}
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
png_ptr->zlib_mem_level = 8;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
png_ptr->zlib_window_bits = 15;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
png_ptr->zlib_method = 8;
deflateInit2(png_ptr->zstream, png_ptr->zlib_level,
png_ptr->zlib_method,
png_ptr->zlib_window_bits,
png_ptr->zlib_mem_level,
png_ptr->zlib_strategy);
png_ptr->zstream->next_out = png_ptr->zbuf;
png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
png_ptr->mode = PNG_HAVE_IHDR;
}
/* write the palette. We are careful not to trust png_color to be in the
correct order for PNG, so people can redefine it to any convient
structure. */
void
png_write_PLTE(png_structp png_ptr, png_colorp palette, int number)
{
int i;
png_colorp pal_ptr;
png_byte buf[3];
if (number == 0 || number > 256)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
png_error(png_ptr, "Invalid number of colors in palette");
}
else
{
png_warning(png_ptr, "Invalid number of colors in palette");
return;
}
}
png_ptr->num_palette = number;
png_write_chunk_start(png_ptr, png_PLTE, number * 3);
for (i = 0, pal_ptr = palette;
i < number;
i++, pal_ptr++)
{
buf[0] = pal_ptr->red;
buf[1] = pal_ptr->green;
buf[2] = pal_ptr->blue;
png_write_chunk_data(png_ptr, buf, (png_uint_32)3);
}
png_write_chunk_end(png_ptr);
png_ptr->mode |= PNG_HAVE_PLTE;
}
/* write an IDAT chunk */
void
png_write_IDAT(png_structp png_ptr, png_bytep data, png_uint_32 length)
{
png_write_chunk(png_ptr, png_IDAT, data, length);
png_ptr->mode |= PNG_HAVE_IDAT;
}
/* write an IEND chunk */
void
png_write_IEND(png_structp png_ptr)
{
png_write_chunk(png_ptr, png_IEND, NULL, (png_uint_32)0);
png_ptr->mode |= PNG_AFTER_IEND;
}
#if defined(PNG_WRITE_gAMA_SUPPORTED)
/* write a gAMA chunk */
void
png_write_gAMA(png_structp png_ptr, double gamma)
{
png_uint_32 igamma;
png_byte buf[4];
/* gamma is saved in 1/100,000ths */
igamma = (png_uint_32)(gamma * 100000.0 + 0.5);
png_save_uint_32(buf, igamma);
png_write_chunk(png_ptr, png_gAMA, buf, (png_uint_32)4);
}
#endif
#if defined(PNG_WRITE_sBIT_SUPPORTED)
/* write the sBIT chunk */
void
png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
{
png_byte buf[4];
int size;
/* make sure we don't depend upon the order of PNG_COLOR_8 */
if (color_type & PNG_COLOR_MASK_COLOR)
{
int maxbits;
maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8:png_ptr->usr_bit_depth;
if (sbit->red == 0 || sbit->red > maxbits ||
sbit->green == 0 || sbit->green > maxbits ||
sbit->blue == 0 || sbit->blue > maxbits)
{
png_warning(png_ptr, "Invalid sBIT depth specified");
return;
}
buf[0] = sbit->red;
buf[1] = sbit->green;
buf[2] = sbit->blue;
size = 3;
}
else
{
if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
{
png_warning(png_ptr, "Invalid sBIT depth specified");
return;
}
buf[0] = sbit->gray;
size = 1;
}
if (color_type & PNG_COLOR_MASK_ALPHA)
{
if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
{
png_warning(png_ptr, "Invalid sBIT depth specified");
return;
}
buf[size++] = sbit->alpha;
}
png_write_chunk(png_ptr, png_sBIT, buf, (png_uint_32)size);
}
#endif
#if defined(PNG_WRITE_cHRM_SUPPORTED)
/* write the cHRM chunk */
void
png_write_cHRM ( png_structp png_ptr, double white_x, double white_y,
double red_x, double red_y, double green_x, double green_y,
double blue_x, double blue_y)
{
png_uint_32 itemp;
png_byte buf[32];
/* each value is saved int 1/100,000ths */
if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
white_x + white_y > 1.0)
{
png_warning(png_ptr, "Invalid cHRM white point specified");
return;
}
itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
png_save_uint_32(buf, itemp);
itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
png_save_uint_32(buf + 4, itemp);
if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
red_x + red_y > 1.0)
{
png_warning(png_ptr, "Invalid cHRM red point specified");
return;
}
itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
png_save_uint_32(buf + 8, itemp);
itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
png_save_uint_32(buf + 12, itemp);
if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
green_x + green_y > 1.0)
{
png_warning(png_ptr, "Invalid cHRM green point specified");
return;
}
itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
png_save_uint_32(buf + 16, itemp);
itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
png_save_uint_32(buf + 20, itemp);
if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
blue_x + blue_y > 1.0)
{
png_warning(png_ptr, "Invalid cHRM blue point specified");
return;
}
itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
png_save_uint_32(buf + 24, itemp);
itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
png_save_uint_32(buf + 28, itemp);
png_write_chunk(png_ptr, png_cHRM, buf, (png_uint_32)32);
}
#endif
#if defined(PNG_WRITE_tRNS_SUPPORTED)
/* write the tRNS chunk */
void
png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
int num_trans, int color_type)
{
png_byte buf[6];
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
if (num_trans <= 0 || num_trans > png_ptr->num_palette)
{
png_warning(png_ptr,"Invalid number of transparent colors specified");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -