📄 pngwutil.c
字号:
/* pngwutil.c - utilities to write a PNG file * * libpng 1.2.5 - October 3, 2002 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2002 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */#define PNG_INTERNAL#include "png.h"#ifdef PNG_WRITE_SUPPORTED/* Place a 32-bit number into a buffer in PNG byte order. We work * with unsigned numbers for convenience, although one supported * ancillary chunk uses signed (two's complement) numbers. */void /* PRIVATE */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);}#if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)/* The png_save_int_32 function assumes integers are stored in two's * complement format. If this isn't the case, then this routine needs to * be modified to write data in two's complement format. */void /* PRIVATE */png_save_int_32(png_bytep buf, png_int_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);}#endif/* Place a 16-bit number into a buffer in PNG byte order. * The parameter is declared unsigned int, not png_uint_16, * just to avoid potential problems on pre-ANSI C compilers. */void /* PRIVATE */png_save_uint_16(png_bytep buf, unsigned int i){ buf[0] = (png_byte)((i >> 8) & 0xff); buf[1] = (png_byte)(i & 0xff);}/* 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 PNGAPIpng_write_chunk(png_structp png_ptr, png_bytep chunk_name, png_bytep data, png_size_t length){ png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); png_write_chunk_data(png_ptr, data, length); png_write_chunk_end(png_ptr);}/* 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 PNGAPIpng_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, png_uint_32 length){ png_byte buf[4]; png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length); /* write the length */ png_save_uint_32(buf, length); png_write_data(png_ptr, buf, (png_size_t)4); /* write the chunk name */ png_write_data(png_ptr, chunk_name, (png_size_t)4); /* reset the crc and run it over the chunk name */ png_reset_crc(png_ptr); png_calculate_crc(png_ptr, chunk_name, (png_size_t)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 PNGAPIpng_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length){ /* write the data, and run the CRC over it */ if (data != NULL && length > 0) { png_calculate_crc(png_ptr, data, length); png_write_data(png_ptr, data, length); }}/* Finish a chunk started with png_write_chunk_start(). */void PNGAPIpng_write_chunk_end(png_structp png_ptr){ png_byte buf[4]; /* write the crc */ png_save_uint_32(buf, png_ptr->crc); png_write_data(png_ptr, buf, (png_size_t)4);}/* Simple function to write the signature. If we have already written * the magic bytes of the signature, or more likely, the PNG stream is * being embedded into another stream and doesn't need its own signature, * we should call png_set_sig_bytes() to tell libpng how many of the * bytes have already been written. */void /* PRIVATE */png_write_sig(png_structp png_ptr){ png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; /* write the rest of the 8 byte signature */ png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], (png_size_t)8 - png_ptr->sig_bytes); if(png_ptr->sig_bytes < 3) png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;}#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)/* * This pair of functions encapsulates the operation of (a) compressing a * text string, and (b) issuing it later as a series of chunk data writes. * The compression_state structure is shared context for these functions * set up by the caller in order to make the whole mess thread-safe. */typedef struct{ char *input; /* the uncompressed input data */ int input_len; /* its length */ int num_output_ptr; /* number of output pointers used */ int max_output_ptr; /* size of output_ptr */ png_charpp output_ptr; /* array of pointers to output */} compression_state;/* compress given text into storage in the png_ptr structure */static int /* PRIVATE */png_text_compress(png_structp png_ptr, png_charp text, png_size_t text_len, int compression, compression_state *comp){ int ret; comp->num_output_ptr = comp->max_output_ptr = 0; comp->output_ptr = NULL; comp->input = NULL; /* we may just want to pass the text right through */ if (compression == PNG_TEXT_COMPRESSION_NONE) { comp->input = text; comp->input_len = text_len; return((int)text_len); } if (compression >= PNG_TEXT_COMPRESSION_LAST) {#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) char msg[50]; sprintf(msg, "Unknown compression type %d", compression); png_warning(png_ptr, msg);#else png_warning(png_ptr, "Unknown compression type");#endif } /* We can't write the chunk until we find out how much data we have, * which means we need to run the compressor first and save the * output. This shouldn't be a problem, as the vast majority of * comments should be reasonable, but we will set up an array of * malloc'd pointers to be sure. * * If we knew the application was well behaved, we could simplify this * greatly by assuming we can always malloc an output buffer large * enough to hold the compressed text ((1001 * text_len / 1000) + 12) * and malloc this directly. The only time this would be a bad idea is * if we can't malloc more than 64K and we have 64K of random input * data, or if the input string is incredibly large (although this * wouldn't cause a failure, just a slowdown due to swapping). */ /* set up the compression buffers */ png_ptr->zstream.avail_in = (uInt)text_len; png_ptr->zstream.next_in = (Bytef *)text; png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; /* this is the same compression loop as in png_write_row() */ do { /* compress the data */ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); if (ret != Z_OK) { /* error */ if (png_ptr->zstream.msg != NULL) png_error(png_ptr, png_ptr->zstream.msg); else png_error(png_ptr, "zlib error"); } /* check to see if we need more room */ if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in) { /* make sure the output array has room */ if (comp->num_output_ptr >= comp->max_output_ptr) { int old_max; old_max = comp->max_output_ptr; comp->max_output_ptr = comp->num_output_ptr + 4; if (comp->output_ptr != NULL) { png_charpp old_ptr; old_ptr = comp->output_ptr; comp->output_ptr = (png_charpp)png_malloc(png_ptr, (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); png_memcpy(comp->output_ptr, old_ptr, old_max * sizeof (png_charp)); png_free(png_ptr, old_ptr); } else comp->output_ptr = (png_charpp)png_malloc(png_ptr, (png_uint_32)(comp->max_output_ptr * sizeof (png_charp))); } /* save the data */ comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size); png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, png_ptr->zbuf_size); comp->num_output_ptr++; /* and reset the buffer */ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; png_ptr->zstream.next_out = png_ptr->zbuf; } /* continue until we don't have any more to compress */ } while (png_ptr->zstream.avail_in); /* finish the compression */ do { /* tell zlib we are finished */ ret = deflate(&png_ptr->zstream, Z_FINISH); if (ret == Z_OK) { /* check to see if we need more room */ if (!(png_ptr->zstream.avail_out)) { /* check to make sure our output array has room */ if (comp->num_output_ptr >= comp->max_output_ptr) { int old_max; old_max = comp->max_output_ptr; comp->max_output_ptr = comp->num_output_ptr + 4; if (comp->output_ptr != NULL) { png_charpp old_ptr; old_ptr = comp->output_ptr; /* This could be optimized to realloc() */ comp->output_ptr = (png_charpp)png_malloc(png_ptr, (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); png_memcpy(comp->output_ptr, old_ptr, old_max * sizeof (png_charp)); png_free(png_ptr, old_ptr); } else comp->output_ptr = (png_charpp)png_malloc(png_ptr, (png_uint_32)(comp->max_output_ptr * sizeof (png_charp))); } /* save off the data */ comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size); png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, png_ptr->zbuf_size); comp->num_output_ptr++; /* and reset the buffer pointers */ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; png_ptr->zstream.next_out = png_ptr->zbuf; } } else if (ret != Z_STREAM_END) { /* we got an error */ if (png_ptr->zstream.msg != NULL) png_error(png_ptr, png_ptr->zstream.msg); else png_error(png_ptr, "zlib error"); } } while (ret != Z_STREAM_END); /* text length is number of buffers plus last buffer */ text_len = png_ptr->zbuf_size * comp->num_output_ptr; if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; return((int)text_len);}/* ship the compressed text out via chunk writes */static void /* PRIVATE */png_write_compressed_data_out(png_structp png_ptr, compression_state *comp){ int i; /* handle the no-compression case */ if (comp->input) { png_write_chunk_data(png_ptr, (png_bytep)comp->input, (png_size_t)comp->input_len); return; } /* write saved output buffers, if any */ for (i = 0; i < comp->num_output_ptr; i++) { png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i], png_ptr->zbuf_size); png_free(png_ptr, comp->output_ptr[i]); comp->output_ptr[i]=NULL; } if (comp->max_output_ptr != 0) png_free(png_ptr, comp->output_ptr); comp->output_ptr=NULL; /* write anything left in zbuf */ if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) png_write_chunk_data(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - png_ptr->zstream.avail_out); /* reset zlib for another zTXt/iTXt or the image data */ deflateReset(&png_ptr->zstream);}#endif/* 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 /* PRIVATE */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){#ifdef PNG_USE_LOCAL_ARRAYS PNG_IHDR;#endif png_byte buf[13]; /* buffer to store the IHDR info */ png_debug(1, "in png_write_IHDR\n"); /* Check that we have valid input data from the application info */ switch (color_type) { case PNG_COLOR_TYPE_GRAY: 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 PNG_COLOR_TYPE_RGB: if (bit_depth != 8 && bit_depth != 16) png_error(png_ptr, "Invalid bit depth for RGB image"); png_ptr->channels = 3; break; case PNG_COLOR_TYPE_PALETTE: 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 PNG_COLOR_TYPE_GRAY_ALPHA: if (bit_depth != 8 && bit_depth != 16) png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); png_ptr->channels = 2; break; case PNG_COLOR_TYPE_RGB_ALPHA: 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 != PNG_COMPRESSION_TYPE_BASE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -