Originally committed as revision 1527 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -0,0 +1,459 @@ | |||
| /* png.c - location for general purpose libpng functions | |||
| * | |||
| * libpng version 1.0.15 - October 3, 2002 | |||
| * 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 | |||
| #define PNG_NO_EXTERN | |||
| #include "png.h" | |||
| /* Generate a compiler error if there is an old png.h in the search path. */ | |||
| typedef version_1_0_15 Your_png_h_is_not_version_1_0_15; | |||
| /* Version information for C files. This had better match the version | |||
| * string defined in png.h. */ | |||
| #ifdef PNG_USE_GLOBAL_ARRAYS | |||
| /* png_libpng_ver was changed to a function in version 1.0.5c */ | |||
| const char png_libpng_ver[18] = "1.0.15"; | |||
| /* png_sig was changed to a function in version 1.0.5c */ | |||
| /* Place to hold the signature string for a PNG file. */ | |||
| const png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; | |||
| /* Invoke global declarations for constant strings for known chunk types */ | |||
| PNG_IHDR; | |||
| PNG_IDAT; | |||
| PNG_IEND; | |||
| PNG_PLTE; | |||
| PNG_bKGD; | |||
| PNG_cHRM; | |||
| PNG_gAMA; | |||
| PNG_hIST; | |||
| PNG_iCCP; | |||
| PNG_iTXt; | |||
| PNG_oFFs; | |||
| PNG_pCAL; | |||
| PNG_sCAL; | |||
| PNG_pHYs; | |||
| PNG_sBIT; | |||
| PNG_sPLT; | |||
| PNG_sRGB; | |||
| PNG_tEXt; | |||
| PNG_tIME; | |||
| PNG_tRNS; | |||
| PNG_zTXt; | |||
| /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ | |||
| /* start of interlace block */ | |||
| const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; | |||
| /* offset to next interlace block */ | |||
| const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; | |||
| /* start of interlace block in the y direction */ | |||
| const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; | |||
| /* offset to next interlace block in the y direction */ | |||
| const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; | |||
| /* width of interlace block (used in assembler routines only) */ | |||
| #ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW | |||
| const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; | |||
| #endif | |||
| /* Height of interlace block. This is not currently used - if you need | |||
| * it, uncomment it here and in png.h | |||
| const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; | |||
| */ | |||
| /* Mask to determine which pixels are valid in a pass */ | |||
| const int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; | |||
| /* Mask to determine which pixels to overwrite while displaying */ | |||
| const int FARDATA png_pass_dsp_mask[] | |||
| = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; | |||
| #endif | |||
| /* Checks whether the supplied bytes match the PNG signature. We allow | |||
| * checking less than the full 8-byte signature so that those apps that | |||
| * already read the first few bytes of a file to determine the file type | |||
| * can simply check the remaining bytes for extra assurance. Returns | |||
| * an integer less than, equal to, or greater than zero if sig is found, | |||
| * respectively, to be less than, to match, or be greater than the correct | |||
| * PNG signature (this is the same behaviour as strcmp, memcmp, etc). | |||
| */ | |||
| int PNGAPI | |||
| png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) | |||
| { | |||
| png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; | |||
| if (num_to_check > 8) | |||
| num_to_check = 8; | |||
| else if (num_to_check < 1) | |||
| return (0); | |||
| if (start > 7) | |||
| return (0); | |||
| if (start + num_to_check > 8) | |||
| num_to_check = 8 - start; | |||
| return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); | |||
| } | |||
| /* Function to allocate memory for zlib and clear it to 0. */ | |||
| #ifdef PNG_1_0_X | |||
| voidpf PNGAPI | |||
| #else | |||
| voidpf /* private */ | |||
| #endif | |||
| png_zalloc(voidpf png_ptr, uInt items, uInt size) | |||
| { | |||
| png_uint_32 num_bytes = (png_uint_32)items * size; | |||
| png_voidp ptr; | |||
| png_structp p=png_ptr; | |||
| png_uint_32 save_flags=p->flags; | |||
| p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; | |||
| ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); | |||
| p->flags=save_flags; | |||
| #ifndef PNG_NO_ZALLOC_ZERO | |||
| if (ptr == NULL) | |||
| return ((voidpf)ptr); | |||
| if (num_bytes > (png_uint_32)0x8000L) | |||
| { | |||
| png_memset(ptr, 0, (png_size_t)0x8000L); | |||
| png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0, | |||
| (png_size_t)(num_bytes - (png_uint_32)0x8000L)); | |||
| } | |||
| else | |||
| { | |||
| png_memset(ptr, 0, (png_size_t)num_bytes); | |||
| } | |||
| #endif | |||
| return ((voidpf)ptr); | |||
| } | |||
| /* function to free memory for zlib */ | |||
| #ifdef PNG_1_0_X | |||
| void PNGAPI | |||
| #else | |||
| void /* private */ | |||
| #endif | |||
| png_zfree(voidpf png_ptr, voidpf ptr) | |||
| { | |||
| png_free((png_structp)png_ptr, (png_voidp)ptr); | |||
| } | |||
| /* Reset the CRC variable to 32 bits of 1's. Care must be taken | |||
| * in case CRC is > 32 bits to leave the top bits 0. | |||
| */ | |||
| void /* PRIVATE */ | |||
| png_reset_crc(png_structp png_ptr) | |||
| { | |||
| png_ptr->crc = crc32(0, Z_NULL, 0); | |||
| } | |||
| /* Calculate the CRC over a section of data. We can only pass as | |||
| * much data to this routine as the largest single buffer size. We | |||
| * also check that this data will actually be used before going to the | |||
| * trouble of calculating it. | |||
| */ | |||
| void /* PRIVATE */ | |||
| png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) | |||
| { | |||
| int need_crc = 1; | |||
| if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ | |||
| { | |||
| if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == | |||
| (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) | |||
| need_crc = 0; | |||
| } | |||
| else /* critical */ | |||
| { | |||
| if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) | |||
| need_crc = 0; | |||
| } | |||
| if (need_crc) | |||
| png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); | |||
| } | |||
| void PNGAPI | |||
| png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, | |||
| int num) | |||
| { | |||
| png_debug(1, "in png_free_data\n"); | |||
| if (png_ptr == NULL || info_ptr == NULL) | |||
| return; | |||
| #if defined(PNG_TEXT_SUPPORTED) | |||
| /* free text item num or (if num == -1) all text items */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) | |||
| #else | |||
| if (mask & PNG_FREE_TEXT) | |||
| #endif | |||
| { | |||
| if (num != -1) | |||
| { | |||
| if (info_ptr->text && info_ptr->text[num].key) | |||
| { | |||
| png_free(png_ptr, info_ptr->text[num].key); | |||
| info_ptr->text[num].key = NULL; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| int i; | |||
| for (i = 0; i < info_ptr->num_text; i++) | |||
| png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); | |||
| png_free(png_ptr, info_ptr->text); | |||
| info_ptr->text = NULL; | |||
| info_ptr->num_text=0; | |||
| } | |||
| } | |||
| #endif | |||
| #if defined(PNG_tRNS_SUPPORTED) | |||
| /* free any tRNS entry */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) | |||
| #else | |||
| if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS)) | |||
| #endif | |||
| { | |||
| png_free(png_ptr, info_ptr->trans); | |||
| info_ptr->valid &= ~PNG_INFO_tRNS; | |||
| #ifndef PNG_FREE_ME_SUPPORTED | |||
| png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; | |||
| #endif | |||
| info_ptr->trans = NULL; | |||
| } | |||
| #endif | |||
| #if defined(PNG_sCAL_SUPPORTED) | |||
| /* free any sCAL entry */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) | |||
| #else | |||
| if (mask & PNG_FREE_SCAL) | |||
| #endif | |||
| { | |||
| #if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) | |||
| png_free(png_ptr, info_ptr->scal_s_width); | |||
| png_free(png_ptr, info_ptr->scal_s_height); | |||
| info_ptr->scal_s_width = NULL; | |||
| info_ptr->scal_s_height = NULL; | |||
| #endif | |||
| info_ptr->valid &= ~PNG_INFO_sCAL; | |||
| } | |||
| #endif | |||
| #if defined(PNG_pCAL_SUPPORTED) | |||
| /* free any pCAL entry */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) | |||
| #else | |||
| if (mask & PNG_FREE_PCAL) | |||
| #endif | |||
| { | |||
| png_free(png_ptr, info_ptr->pcal_purpose); | |||
| png_free(png_ptr, info_ptr->pcal_units); | |||
| info_ptr->pcal_purpose = NULL; | |||
| info_ptr->pcal_units = NULL; | |||
| if (info_ptr->pcal_params != NULL) | |||
| { | |||
| int i; | |||
| for (i = 0; i < (int)info_ptr->pcal_nparams; i++) | |||
| { | |||
| png_free(png_ptr, info_ptr->pcal_params[i]); | |||
| info_ptr->pcal_params[i]=NULL; | |||
| } | |||
| png_free(png_ptr, info_ptr->pcal_params); | |||
| info_ptr->pcal_params = NULL; | |||
| } | |||
| info_ptr->valid &= ~PNG_INFO_pCAL; | |||
| } | |||
| #endif | |||
| #if defined(PNG_iCCP_SUPPORTED) | |||
| /* free any iCCP entry */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) | |||
| #else | |||
| if (mask & PNG_FREE_ICCP) | |||
| #endif | |||
| { | |||
| png_free(png_ptr, info_ptr->iccp_name); | |||
| png_free(png_ptr, info_ptr->iccp_profile); | |||
| info_ptr->iccp_name = NULL; | |||
| info_ptr->iccp_profile = NULL; | |||
| info_ptr->valid &= ~PNG_INFO_iCCP; | |||
| } | |||
| #endif | |||
| #if defined(PNG_sPLT_SUPPORTED) | |||
| /* free a given sPLT entry, or (if num == -1) all sPLT entries */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) | |||
| #else | |||
| if (mask & PNG_FREE_SPLT) | |||
| #endif | |||
| { | |||
| if (num != -1) | |||
| { | |||
| if(info_ptr->splt_palettes) | |||
| { | |||
| png_free(png_ptr, info_ptr->splt_palettes[num].name); | |||
| png_free(png_ptr, info_ptr->splt_palettes[num].entries); | |||
| info_ptr->splt_palettes[num].name = NULL; | |||
| info_ptr->splt_palettes[num].entries = NULL; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if(info_ptr->splt_palettes_num) | |||
| { | |||
| int i; | |||
| for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) | |||
| png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); | |||
| png_free(png_ptr, info_ptr->splt_palettes); | |||
| info_ptr->splt_palettes = NULL; | |||
| info_ptr->splt_palettes_num = 0; | |||
| } | |||
| info_ptr->valid &= ~PNG_INFO_sPLT; | |||
| } | |||
| } | |||
| #endif | |||
| #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) | |||
| #else | |||
| if (mask & PNG_FREE_UNKN) | |||
| #endif | |||
| { | |||
| if (num != -1) | |||
| { | |||
| if(info_ptr->unknown_chunks) | |||
| { | |||
| png_free(png_ptr, info_ptr->unknown_chunks[num].data); | |||
| info_ptr->unknown_chunks[num].data = NULL; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| int i; | |||
| if(info_ptr->unknown_chunks_num) | |||
| { | |||
| for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) | |||
| png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); | |||
| png_free(png_ptr, info_ptr->unknown_chunks); | |||
| info_ptr->unknown_chunks = NULL; | |||
| info_ptr->unknown_chunks_num = 0; | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| #if defined(PNG_hIST_SUPPORTED) | |||
| /* free any hIST entry */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_HIST) & info_ptr->free_me) | |||
| #else | |||
| if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST)) | |||
| #endif | |||
| { | |||
| png_free(png_ptr, info_ptr->hist); | |||
| info_ptr->hist = NULL; | |||
| info_ptr->valid &= ~PNG_INFO_hIST; | |||
| #ifndef PNG_FREE_ME_SUPPORTED | |||
| png_ptr->flags &= ~PNG_FLAG_FREE_HIST; | |||
| #endif | |||
| } | |||
| #endif | |||
| /* free any PLTE entry that was internally allocated */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) | |||
| #else | |||
| if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE)) | |||
| #endif | |||
| { | |||
| png_zfree(png_ptr, info_ptr->palette); | |||
| info_ptr->palette = NULL; | |||
| info_ptr->valid &= ~PNG_INFO_PLTE; | |||
| #ifndef PNG_FREE_ME_SUPPORTED | |||
| png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; | |||
| #endif | |||
| info_ptr->num_palette = 0; | |||
| } | |||
| #if defined(PNG_INFO_IMAGE_SUPPORTED) | |||
| /* free any image bits attached to the info structure */ | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) | |||
| #else | |||
| if (mask & PNG_FREE_ROWS) | |||
| #endif | |||
| { | |||
| if(info_ptr->row_pointers) | |||
| { | |||
| int row; | |||
| for (row = 0; row < (int)info_ptr->height; row++) | |||
| { | |||
| png_free(png_ptr, info_ptr->row_pointers[row]); | |||
| info_ptr->row_pointers[row]=NULL; | |||
| } | |||
| png_free(png_ptr, info_ptr->row_pointers); | |||
| info_ptr->row_pointers=NULL; | |||
| } | |||
| info_ptr->valid &= ~PNG_INFO_IDAT; | |||
| } | |||
| #endif | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if(num == -1) | |||
| info_ptr->free_me &= ~mask; | |||
| else | |||
| info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); | |||
| #endif | |||
| } | |||
| #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED | |||
| int PNGAPI | |||
| png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) | |||
| { | |||
| /* check chunk_name and return "keep" value if it's on the list, else 0 */ | |||
| int i; | |||
| png_bytep p; | |||
| if((png_ptr == NULL && chunk_name == NULL) || png_ptr->num_chunk_list<=0) | |||
| return 0; | |||
| p=png_ptr->chunk_list+png_ptr->num_chunk_list*5-5; | |||
| for (i = png_ptr->num_chunk_list; i; i--, p-=5) | |||
| if (!png_memcmp(chunk_name, p, 4)) | |||
| return ((int)*(p+4)); | |||
| return 0; | |||
| } | |||
| #endif | |||
| void png_info_init(png_info *info_ptr) | |||
| { | |||
| memset(info_ptr, 0, sizeof(png_info)); | |||
| } | |||
| @@ -0,0 +1,824 @@ | |||
| /* pngread.c - read a PNG file | |||
| * | |||
| * libpng 1.0.15 - 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.) | |||
| * | |||
| * This file contains routines that an application calls directly to | |||
| * read a PNG file or stream. | |||
| */ | |||
| #define PNG_INTERNAL | |||
| #include "png.h" | |||
| void png_read_init(png_struct *png_ptr) | |||
| { | |||
| /* reset all variables to 0 */ | |||
| memset(png_ptr, 0, sizeof (png_struct)); | |||
| /* initialize zbuf - compression buffer */ | |||
| png_ptr->zbuf_size = PNG_ZBUF_SIZE; | |||
| png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, | |||
| (png_uint_32)png_ptr->zbuf_size); | |||
| png_ptr->zstream.zalloc = png_zalloc; | |||
| png_ptr->zstream.zfree = png_zfree; | |||
| png_ptr->zstream.opaque = (voidpf)png_ptr; | |||
| switch (inflateInit(&png_ptr->zstream)) | |||
| { | |||
| case Z_OK: /* Do nothing */ break; | |||
| case Z_MEM_ERROR: | |||
| case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break; | |||
| case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break; | |||
| default: png_error(png_ptr, "Unknown zlib error"); | |||
| } | |||
| png_ptr->zstream.next_out = png_ptr->zbuf; | |||
| png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; | |||
| } | |||
| /* Read the information before the actual image data. This has been | |||
| * changed in v0.90 to allow reading a file that already has the magic | |||
| * bytes read from the stream. You can tell libpng how many bytes have | |||
| * been read from the beginning of the stream (up to the maximum of 8) | |||
| * via png_set_sig_bytes(), and we will only check the remaining bytes | |||
| * here. The application can then have access to the signature bytes we | |||
| * read if it is determined that this isn't a valid PNG file. | |||
| */ | |||
| void PNGAPI | |||
| png_read_info(png_structp png_ptr, png_infop info_ptr) | |||
| { | |||
| png_debug(1, "in png_read_info\n"); | |||
| /* If we haven't checked all of the PNG signature bytes, do so now. */ | |||
| if (png_ptr->sig_bytes < 8) | |||
| { | |||
| png_size_t num_checked = png_ptr->sig_bytes, | |||
| num_to_check = 8 - num_checked; | |||
| png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); | |||
| png_ptr->sig_bytes = 8; | |||
| if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) | |||
| { | |||
| if (num_checked < 4 && | |||
| png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) | |||
| png_error(png_ptr, "Not a PNG file"); | |||
| else | |||
| png_error(png_ptr, "PNG file corrupted by ASCII conversion"); | |||
| } | |||
| if (num_checked < 3) | |||
| png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; | |||
| } | |||
| for(;;) | |||
| { | |||
| #ifdef PNG_USE_LOCAL_ARRAYS | |||
| PNG_IHDR; | |||
| PNG_IDAT; | |||
| PNG_IEND; | |||
| PNG_PLTE; | |||
| #if defined(PNG_READ_bKGD_SUPPORTED) | |||
| PNG_bKGD; | |||
| #endif | |||
| #if defined(PNG_READ_cHRM_SUPPORTED) | |||
| PNG_cHRM; | |||
| #endif | |||
| #if defined(PNG_READ_gAMA_SUPPORTED) | |||
| PNG_gAMA; | |||
| #endif | |||
| #if defined(PNG_READ_hIST_SUPPORTED) | |||
| PNG_hIST; | |||
| #endif | |||
| #if defined(PNG_READ_iCCP_SUPPORTED) | |||
| PNG_iCCP; | |||
| #endif | |||
| #if defined(PNG_READ_iTXt_SUPPORTED) | |||
| PNG_iTXt; | |||
| #endif | |||
| #if defined(PNG_READ_oFFs_SUPPORTED) | |||
| PNG_oFFs; | |||
| #endif | |||
| #if defined(PNG_READ_pCAL_SUPPORTED) | |||
| PNG_pCAL; | |||
| #endif | |||
| #if defined(PNG_READ_pHYs_SUPPORTED) | |||
| PNG_pHYs; | |||
| #endif | |||
| #if defined(PNG_READ_sBIT_SUPPORTED) | |||
| PNG_sBIT; | |||
| #endif | |||
| #if defined(PNG_READ_sCAL_SUPPORTED) | |||
| PNG_sCAL; | |||
| #endif | |||
| #if defined(PNG_READ_sPLT_SUPPORTED) | |||
| PNG_sPLT; | |||
| #endif | |||
| #if defined(PNG_READ_sRGB_SUPPORTED) | |||
| PNG_sRGB; | |||
| #endif | |||
| #if defined(PNG_READ_tEXt_SUPPORTED) | |||
| PNG_tEXt; | |||
| #endif | |||
| #if defined(PNG_READ_tIME_SUPPORTED) | |||
| PNG_tIME; | |||
| #endif | |||
| #if defined(PNG_READ_tRNS_SUPPORTED) | |||
| PNG_tRNS; | |||
| #endif | |||
| #if defined(PNG_READ_zTXt_SUPPORTED) | |||
| PNG_zTXt; | |||
| #endif | |||
| #endif /* PNG_GLOBAL_ARRAYS */ | |||
| png_byte chunk_length[4]; | |||
| png_uint_32 length; | |||
| png_read_data(png_ptr, chunk_length, 4); | |||
| length = png_get_uint_32(chunk_length); | |||
| png_reset_crc(png_ptr); | |||
| png_crc_read(png_ptr, png_ptr->chunk_name, 4); | |||
| png_debug2(0, "Reading %s chunk, length=%lu.\n", png_ptr->chunk_name, | |||
| length); | |||
| if (length > PNG_MAX_UINT) | |||
| png_error(png_ptr, "Invalid chunk length."); | |||
| /* This should be a binary subdivision search or a hash for | |||
| * matching the chunk name rather than a linear search. | |||
| */ | |||
| if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) | |||
| png_handle_IHDR(png_ptr, info_ptr, length); | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) | |||
| png_handle_IEND(png_ptr, info_ptr, length); | |||
| #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED | |||
| else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) | |||
| { | |||
| if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |||
| png_ptr->mode |= PNG_HAVE_IDAT; | |||
| png_handle_unknown(png_ptr, info_ptr, length); | |||
| if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) | |||
| png_ptr->mode |= PNG_HAVE_PLTE; | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |||
| { | |||
| if (!(png_ptr->mode & PNG_HAVE_IHDR)) | |||
| png_error(png_ptr, "Missing IHDR before IDAT"); | |||
| else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && | |||
| !(png_ptr->mode & PNG_HAVE_PLTE)) | |||
| png_error(png_ptr, "Missing PLTE before IDAT"); | |||
| break; | |||
| } | |||
| } | |||
| #endif | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) | |||
| png_handle_PLTE(png_ptr, info_ptr, length); | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |||
| { | |||
| if (!(png_ptr->mode & PNG_HAVE_IHDR)) | |||
| png_error(png_ptr, "Missing IHDR before IDAT"); | |||
| else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && | |||
| !(png_ptr->mode & PNG_HAVE_PLTE)) | |||
| png_error(png_ptr, "Missing PLTE before IDAT"); | |||
| png_ptr->idat_size = length; | |||
| png_ptr->mode |= PNG_HAVE_IDAT; | |||
| break; | |||
| } | |||
| #if defined(PNG_READ_bKGD_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) | |||
| png_handle_bKGD(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_cHRM_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) | |||
| png_handle_cHRM(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_gAMA_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) | |||
| png_handle_gAMA(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_hIST_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) | |||
| png_handle_hIST(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_oFFs_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) | |||
| png_handle_oFFs(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_pCAL_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) | |||
| png_handle_pCAL(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sCAL_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) | |||
| png_handle_sCAL(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_pHYs_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) | |||
| png_handle_pHYs(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sBIT_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) | |||
| png_handle_sBIT(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sRGB_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) | |||
| png_handle_sRGB(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_iCCP_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) | |||
| png_handle_iCCP(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sPLT_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) | |||
| png_handle_sPLT(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_tEXt_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) | |||
| png_handle_tEXt(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_tIME_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) | |||
| png_handle_tIME(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_tRNS_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) | |||
| png_handle_tRNS(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_zTXt_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) | |||
| png_handle_zTXt(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_iTXt_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) | |||
| png_handle_iTXt(png_ptr, info_ptr, length); | |||
| #endif | |||
| else | |||
| png_handle_unknown(png_ptr, info_ptr, length); | |||
| } | |||
| } | |||
| /* Initialize palette, background, etc, after transformations | |||
| * are set, but before any reading takes place. This allows | |||
| * the user to obtain a gamma-corrected palette, for example. | |||
| * If the user doesn't call this, we will do it ourselves. | |||
| */ | |||
| void PNGAPI | |||
| png_start_read_image(png_structp png_ptr) | |||
| { | |||
| png_debug(1, "in png_start_read_image\n"); | |||
| if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) | |||
| png_read_start_row(png_ptr); | |||
| } | |||
| void PNGAPI | |||
| png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) | |||
| { | |||
| #ifdef PNG_USE_LOCAL_ARRAYS | |||
| PNG_IDAT; | |||
| const int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; | |||
| const int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; | |||
| #endif | |||
| int ret; | |||
| png_debug2(1, "in png_read_row (row %lu, pass %d)\n", | |||
| png_ptr->row_number, png_ptr->pass); | |||
| if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) | |||
| png_read_start_row(png_ptr); | |||
| if (png_ptr->row_number == 0 && png_ptr->pass == 0) | |||
| { | |||
| /* check for transforms that have been set but were defined out */ | |||
| #if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_INVERT_MONO) | |||
| png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined."); | |||
| #endif | |||
| #if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_FILLER) | |||
| png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined."); | |||
| #endif | |||
| #if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_PACKSWAP) | |||
| png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined."); | |||
| #endif | |||
| #if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_PACK) | |||
| png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined."); | |||
| #endif | |||
| #if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_SHIFT) | |||
| png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined."); | |||
| #endif | |||
| #if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_BGR) | |||
| png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined."); | |||
| #endif | |||
| #if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_SWAP_BYTES) | |||
| png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined."); | |||
| #endif | |||
| } | |||
| #if defined(PNG_READ_INTERLACING_SUPPORTED) | |||
| /* if interlaced and we do not need a new row, combine row and return */ | |||
| if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) | |||
| { | |||
| switch (png_ptr->pass) | |||
| { | |||
| case 0: | |||
| if (png_ptr->row_number & 0x07) | |||
| { | |||
| if (dsp_row != NULL) | |||
| png_combine_row(png_ptr, dsp_row, | |||
| png_pass_dsp_mask[png_ptr->pass]); | |||
| png_read_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 1: | |||
| if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) | |||
| { | |||
| if (dsp_row != NULL) | |||
| png_combine_row(png_ptr, dsp_row, | |||
| png_pass_dsp_mask[png_ptr->pass]); | |||
| png_read_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 2: | |||
| if ((png_ptr->row_number & 0x07) != 4) | |||
| { | |||
| if (dsp_row != NULL && (png_ptr->row_number & 4)) | |||
| png_combine_row(png_ptr, dsp_row, | |||
| png_pass_dsp_mask[png_ptr->pass]); | |||
| png_read_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 3: | |||
| if ((png_ptr->row_number & 3) || png_ptr->width < 3) | |||
| { | |||
| if (dsp_row != NULL) | |||
| png_combine_row(png_ptr, dsp_row, | |||
| png_pass_dsp_mask[png_ptr->pass]); | |||
| png_read_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 4: | |||
| if ((png_ptr->row_number & 3) != 2) | |||
| { | |||
| if (dsp_row != NULL && (png_ptr->row_number & 2)) | |||
| png_combine_row(png_ptr, dsp_row, | |||
| png_pass_dsp_mask[png_ptr->pass]); | |||
| png_read_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 5: | |||
| if ((png_ptr->row_number & 1) || png_ptr->width < 2) | |||
| { | |||
| if (dsp_row != NULL) | |||
| png_combine_row(png_ptr, dsp_row, | |||
| png_pass_dsp_mask[png_ptr->pass]); | |||
| png_read_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 6: | |||
| if (!(png_ptr->row_number & 1)) | |||
| { | |||
| png_read_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| #endif | |||
| if (!(png_ptr->mode & PNG_HAVE_IDAT)) | |||
| png_error(png_ptr, "Invalid attempt to read row data"); | |||
| png_ptr->zstream.next_out = png_ptr->row_buf; | |||
| png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; | |||
| do | |||
| { | |||
| if (!(png_ptr->zstream.avail_in)) | |||
| { | |||
| while (!png_ptr->idat_size) | |||
| { | |||
| png_byte chunk_length[4]; | |||
| png_crc_finish(png_ptr, 0); | |||
| png_read_data(png_ptr, chunk_length, 4); | |||
| png_ptr->idat_size = png_get_uint_32(chunk_length); | |||
| if (png_ptr->idat_size > PNG_MAX_UINT) | |||
| png_error(png_ptr, "Invalid chunk length."); | |||
| png_reset_crc(png_ptr); | |||
| png_crc_read(png_ptr, png_ptr->chunk_name, 4); | |||
| if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |||
| png_error(png_ptr, "Not enough image data"); | |||
| } | |||
| png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; | |||
| png_ptr->zstream.next_in = png_ptr->zbuf; | |||
| if (png_ptr->zbuf_size > png_ptr->idat_size) | |||
| png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; | |||
| png_crc_read(png_ptr, png_ptr->zbuf, | |||
| (png_size_t)png_ptr->zstream.avail_in); | |||
| png_ptr->idat_size -= png_ptr->zstream.avail_in; | |||
| } | |||
| ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); | |||
| if (ret == Z_STREAM_END) | |||
| { | |||
| if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || | |||
| png_ptr->idat_size) | |||
| png_error(png_ptr, "Extra compressed data"); | |||
| png_ptr->mode |= PNG_AFTER_IDAT; | |||
| png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; | |||
| break; | |||
| } | |||
| if (ret != Z_OK) | |||
| png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : | |||
| "Decompression error"); | |||
| } while (png_ptr->zstream.avail_out); | |||
| png_ptr->row_info.color_type = png_ptr->color_type; | |||
| png_ptr->row_info.width = png_ptr->iwidth; | |||
| png_ptr->row_info.channels = png_ptr->channels; | |||
| png_ptr->row_info.bit_depth = png_ptr->bit_depth; | |||
| png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; | |||
| png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * | |||
| (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); | |||
| if(png_ptr->row_buf[0]) | |||
| png_read_filter_row(png_ptr, &(png_ptr->row_info), | |||
| png_ptr->row_buf + 1, png_ptr->prev_row + 1, | |||
| (int)(png_ptr->row_buf[0])); | |||
| png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, | |||
| png_ptr->rowbytes + 1); | |||
| #if defined(PNG_MNG_FEATURES_SUPPORTED) | |||
| if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && | |||
| (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) | |||
| { | |||
| /* Intrapixel differencing */ | |||
| png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); | |||
| } | |||
| #endif | |||
| #if defined(PNG_READ_INTERLACING_SUPPORTED) | |||
| /* blow up interlaced rows to full size */ | |||
| if (png_ptr->interlaced && | |||
| (png_ptr->transformations & PNG_INTERLACE)) | |||
| { | |||
| if (png_ptr->pass < 6) | |||
| /* old interface (pre-1.0.9): | |||
| png_do_read_interlace(&(png_ptr->row_info), | |||
| png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); | |||
| */ | |||
| png_do_read_interlace(png_ptr); | |||
| if (dsp_row != NULL) | |||
| png_combine_row(png_ptr, dsp_row, | |||
| png_pass_dsp_mask[png_ptr->pass]); | |||
| if (row != NULL) | |||
| png_combine_row(png_ptr, row, | |||
| png_pass_mask[png_ptr->pass]); | |||
| } | |||
| else | |||
| #endif | |||
| { | |||
| if (row != NULL) | |||
| png_combine_row(png_ptr, row, 0xff); | |||
| if (dsp_row != NULL) | |||
| png_combine_row(png_ptr, dsp_row, 0xff); | |||
| } | |||
| png_read_finish_row(png_ptr); | |||
| if (png_ptr->read_row_fn != NULL) | |||
| (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); | |||
| } | |||
| /* Read the end of the PNG file. Will not read past the end of the | |||
| * file, will verify the end is accurate, and will read any comments | |||
| * or time information at the end of the file, if info is not NULL. | |||
| */ | |||
| void PNGAPI | |||
| png_read_end(png_structp png_ptr, png_infop info_ptr) | |||
| { | |||
| png_byte chunk_length[4]; | |||
| png_uint_32 length; | |||
| png_debug(1, "in png_read_end\n"); | |||
| png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ | |||
| do | |||
| { | |||
| #ifdef PNG_USE_LOCAL_ARRAYS | |||
| PNG_IHDR; | |||
| PNG_IDAT; | |||
| PNG_IEND; | |||
| PNG_PLTE; | |||
| #if defined(PNG_READ_bKGD_SUPPORTED) | |||
| PNG_bKGD; | |||
| #endif | |||
| #if defined(PNG_READ_cHRM_SUPPORTED) | |||
| PNG_cHRM; | |||
| #endif | |||
| #if defined(PNG_READ_gAMA_SUPPORTED) | |||
| PNG_gAMA; | |||
| #endif | |||
| #if defined(PNG_READ_hIST_SUPPORTED) | |||
| PNG_hIST; | |||
| #endif | |||
| #if defined(PNG_READ_iCCP_SUPPORTED) | |||
| PNG_iCCP; | |||
| #endif | |||
| #if defined(PNG_READ_iTXt_SUPPORTED) | |||
| PNG_iTXt; | |||
| #endif | |||
| #if defined(PNG_READ_oFFs_SUPPORTED) | |||
| PNG_oFFs; | |||
| #endif | |||
| #if defined(PNG_READ_pCAL_SUPPORTED) | |||
| PNG_pCAL; | |||
| #endif | |||
| #if defined(PNG_READ_pHYs_SUPPORTED) | |||
| PNG_pHYs; | |||
| #endif | |||
| #if defined(PNG_READ_sBIT_SUPPORTED) | |||
| PNG_sBIT; | |||
| #endif | |||
| #if defined(PNG_READ_sCAL_SUPPORTED) | |||
| PNG_sCAL; | |||
| #endif | |||
| #if defined(PNG_READ_sPLT_SUPPORTED) | |||
| PNG_sPLT; | |||
| #endif | |||
| #if defined(PNG_READ_sRGB_SUPPORTED) | |||
| PNG_sRGB; | |||
| #endif | |||
| #if defined(PNG_READ_tEXt_SUPPORTED) | |||
| PNG_tEXt; | |||
| #endif | |||
| #if defined(PNG_READ_tIME_SUPPORTED) | |||
| PNG_tIME; | |||
| #endif | |||
| #if defined(PNG_READ_tRNS_SUPPORTED) | |||
| PNG_tRNS; | |||
| #endif | |||
| #if defined(PNG_READ_zTXt_SUPPORTED) | |||
| PNG_zTXt; | |||
| #endif | |||
| #endif /* PNG_GLOBAL_ARRAYS */ | |||
| png_read_data(png_ptr, chunk_length, 4); | |||
| length = png_get_uint_32(chunk_length); | |||
| png_reset_crc(png_ptr); | |||
| png_crc_read(png_ptr, png_ptr->chunk_name, 4); | |||
| png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name); | |||
| if (length > PNG_MAX_UINT) | |||
| png_error(png_ptr, "Invalid chunk length."); | |||
| if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) | |||
| png_handle_IHDR(png_ptr, info_ptr, length); | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) | |||
| png_handle_IEND(png_ptr, info_ptr, length); | |||
| #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED | |||
| else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) | |||
| { | |||
| if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |||
| { | |||
| if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) | |||
| png_error(png_ptr, "Too many IDAT's found"); | |||
| } | |||
| else | |||
| png_ptr->mode |= PNG_AFTER_IDAT; | |||
| png_handle_unknown(png_ptr, info_ptr, length); | |||
| if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) | |||
| png_ptr->mode |= PNG_HAVE_PLTE; | |||
| } | |||
| #endif | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |||
| { | |||
| /* Zero length IDATs are legal after the last IDAT has been | |||
| * read, but not after other chunks have been read. | |||
| */ | |||
| if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) | |||
| png_error(png_ptr, "Too many IDAT's found"); | |||
| png_crc_finish(png_ptr, length); | |||
| } | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) | |||
| png_handle_PLTE(png_ptr, info_ptr, length); | |||
| #if defined(PNG_READ_bKGD_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) | |||
| png_handle_bKGD(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_cHRM_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) | |||
| png_handle_cHRM(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_gAMA_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) | |||
| png_handle_gAMA(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_hIST_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) | |||
| png_handle_hIST(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_oFFs_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) | |||
| png_handle_oFFs(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_pCAL_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) | |||
| png_handle_pCAL(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sCAL_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) | |||
| png_handle_sCAL(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_pHYs_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) | |||
| png_handle_pHYs(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sBIT_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) | |||
| png_handle_sBIT(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sRGB_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) | |||
| png_handle_sRGB(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_iCCP_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) | |||
| png_handle_iCCP(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_sPLT_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) | |||
| png_handle_sPLT(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_tEXt_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) | |||
| png_handle_tEXt(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_tIME_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) | |||
| png_handle_tIME(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_tRNS_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) | |||
| png_handle_tRNS(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_zTXt_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) | |||
| png_handle_zTXt(png_ptr, info_ptr, length); | |||
| #endif | |||
| #if defined(PNG_READ_iTXt_SUPPORTED) | |||
| else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) | |||
| png_handle_iTXt(png_ptr, info_ptr, length); | |||
| #endif | |||
| else | |||
| png_handle_unknown(png_ptr, info_ptr, length); | |||
| } while (!(png_ptr->mode & PNG_HAVE_IEND)); | |||
| } | |||
| /* free all memory used by the read (old method) */ | |||
| void /* PRIVATE */ | |||
| png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr) | |||
| { | |||
| #ifdef PNG_SETJMP_SUPPORTED | |||
| jmp_buf tmp_jmp; | |||
| #endif | |||
| #ifdef PNG_USER_MEM_SUPPORTED | |||
| png_free_ptr free_fn; | |||
| #endif | |||
| png_debug(1, "in png_read_destroy\n"); | |||
| png_free(png_ptr, png_ptr->zbuf); | |||
| png_free(png_ptr, png_ptr->big_row_buf); | |||
| png_free(png_ptr, png_ptr->prev_row); | |||
| #if defined(PNG_READ_DITHER_SUPPORTED) | |||
| png_free(png_ptr, png_ptr->palette_lookup); | |||
| png_free(png_ptr, png_ptr->dither_index); | |||
| #endif | |||
| #if defined(PNG_READ_GAMMA_SUPPORTED) | |||
| png_free(png_ptr, png_ptr->gamma_table); | |||
| #endif | |||
| #if defined(PNG_READ_BACKGROUND_SUPPORTED) | |||
| png_free(png_ptr, png_ptr->gamma_from_1); | |||
| png_free(png_ptr, png_ptr->gamma_to_1); | |||
| #endif | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if (png_ptr->free_me & PNG_FREE_PLTE) | |||
| png_zfree(png_ptr, png_ptr->palette); | |||
| png_ptr->free_me &= ~PNG_FREE_PLTE; | |||
| #else | |||
| if (png_ptr->flags & PNG_FLAG_FREE_PLTE) | |||
| png_zfree(png_ptr, png_ptr->palette); | |||
| png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; | |||
| #endif | |||
| #if defined(PNG_tRNS_SUPPORTED) || \ | |||
| defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if (png_ptr->free_me & PNG_FREE_TRNS) | |||
| png_free(png_ptr, png_ptr->trans); | |||
| png_ptr->free_me &= ~PNG_FREE_TRNS; | |||
| #else | |||
| if (png_ptr->flags & PNG_FLAG_FREE_TRNS) | |||
| png_free(png_ptr, png_ptr->trans); | |||
| png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; | |||
| #endif | |||
| #endif | |||
| #if defined(PNG_READ_hIST_SUPPORTED) | |||
| #ifdef PNG_FREE_ME_SUPPORTED | |||
| if (png_ptr->free_me & PNG_FREE_HIST) | |||
| png_free(png_ptr, png_ptr->hist); | |||
| png_ptr->free_me &= ~PNG_FREE_HIST; | |||
| #else | |||
| if (png_ptr->flags & PNG_FLAG_FREE_HIST) | |||
| png_free(png_ptr, png_ptr->hist); | |||
| png_ptr->flags &= ~PNG_FLAG_FREE_HIST; | |||
| #endif | |||
| #endif | |||
| #if defined(PNG_READ_GAMMA_SUPPORTED) | |||
| if (png_ptr->gamma_16_table != NULL) | |||
| { | |||
| int i; | |||
| int istop = (1 << (8 - png_ptr->gamma_shift)); | |||
| for (i = 0; i < istop; i++) | |||
| { | |||
| png_free(png_ptr, png_ptr->gamma_16_table[i]); | |||
| } | |||
| png_free(png_ptr, png_ptr->gamma_16_table); | |||
| } | |||
| #if defined(PNG_READ_BACKGROUND_SUPPORTED) | |||
| if (png_ptr->gamma_16_from_1 != NULL) | |||
| { | |||
| int i; | |||
| int istop = (1 << (8 - png_ptr->gamma_shift)); | |||
| for (i = 0; i < istop; i++) | |||
| { | |||
| png_free(png_ptr, png_ptr->gamma_16_from_1[i]); | |||
| } | |||
| png_free(png_ptr, png_ptr->gamma_16_from_1); | |||
| } | |||
| if (png_ptr->gamma_16_to_1 != NULL) | |||
| { | |||
| int i; | |||
| int istop = (1 << (8 - png_ptr->gamma_shift)); | |||
| for (i = 0; i < istop; i++) | |||
| { | |||
| png_free(png_ptr, png_ptr->gamma_16_to_1[i]); | |||
| } | |||
| png_free(png_ptr, png_ptr->gamma_16_to_1); | |||
| } | |||
| #endif | |||
| #endif | |||
| #if defined(PNG_TIME_RFC1123_SUPPORTED) | |||
| png_free(png_ptr, png_ptr->time_buffer); | |||
| #endif | |||
| inflateEnd(&png_ptr->zstream); | |||
| #ifdef PNG_PROGRESSIVE_READ_SUPPORTED | |||
| png_free(png_ptr, png_ptr->save_buffer); | |||
| #endif | |||
| #ifdef PNG_PROGRESSIVE_READ_SUPPORTED | |||
| #ifdef PNG_TEXT_SUPPORTED | |||
| png_free(png_ptr, png_ptr->current_text); | |||
| #endif /* PNG_TEXT_SUPPORTED */ | |||
| #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ | |||
| /* Save the important info out of the png_struct, in case it is | |||
| * being used again. | |||
| */ | |||
| #ifdef PNG_SETJMP_SUPPORTED | |||
| png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); | |||
| #endif | |||
| #ifdef PNG_USER_MEM_SUPPORTED | |||
| free_fn = png_ptr->free_fn; | |||
| #endif | |||
| png_memset(png_ptr, 0, sizeof (png_struct)); | |||
| #ifdef PNG_USER_MEM_SUPPORTED | |||
| png_ptr->free_fn = free_fn; | |||
| #endif | |||
| #ifdef PNG_SETJMP_SUPPORTED | |||
| png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); | |||
| #endif | |||
| } | |||
| @@ -0,0 +1,943 @@ | |||
| /* pngwrite.c - general routines to write a PNG file | |||
| * | |||
| * libpng 1.0.15 - 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.) | |||
| */ | |||
| /* get internal access to png.h */ | |||
| #define PNG_INTERNAL | |||
| #include "png.h" | |||
| #ifdef PNG_WRITE_SUPPORTED | |||
| void png_write_init(png_struct *png_ptr) | |||
| { | |||
| png_debug(1, "in png_write_init_3\n"); | |||
| /* reset all variables to 0 */ | |||
| png_memset(png_ptr, 0, sizeof (png_struct)); | |||
| /* initialize zbuf - compression buffer */ | |||
| png_ptr->zbuf_size = PNG_ZBUF_SIZE; | |||
| png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, | |||
| (png_uint_32)png_ptr->zbuf_size); | |||
| #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) | |||
| png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, | |||
| 1, png_doublep_NULL, png_doublep_NULL); | |||
| #endif | |||
| } | |||
| /* Writes all the PNG information. This is the suggested way to use the | |||
| * library. If you have a new chunk to add, make a function to write it, | |||
| * and put it in the correct location here. If you want the chunk written | |||
| * after the image data, put it in png_write_end(). I strongly encourage | |||
| * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing | |||
| * the chunk, as that will keep the code from breaking if you want to just | |||
| * write a plain PNG file. If you have long comments, I suggest writing | |||
| * them in png_write_end(), and compressing them. | |||
| */ | |||
| void PNGAPI | |||
| png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) | |||
| { | |||
| png_debug(1, "in png_write_info_before_PLTE\n"); | |||
| if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) | |||
| { | |||
| png_write_sig(png_ptr); /* write PNG signature */ | |||
| #if defined(PNG_MNG_FEATURES_SUPPORTED) | |||
| if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted)) | |||
| { | |||
| png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n"); | |||
| png_ptr->mng_features_permitted=0; | |||
| } | |||
| #endif | |||
| /* write IHDR information. */ | |||
| png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, | |||
| info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, | |||
| info_ptr->filter_type, | |||
| #if defined(PNG_WRITE_INTERLACING_SUPPORTED) | |||
| info_ptr->interlace_type); | |||
| #else | |||
| 0); | |||
| #endif | |||
| /* the rest of these check to see if the valid field has the appropriate | |||
| flag set, and if it does, writes the chunk. */ | |||
| #if defined(PNG_WRITE_gAMA_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_gAMA) | |||
| { | |||
| # ifdef PNG_FLOATING_POINT_SUPPORTED | |||
| png_write_gAMA(png_ptr, info_ptr->gamma); | |||
| #else | |||
| #ifdef PNG_FIXED_POINT_SUPPORTED | |||
| png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); | |||
| # endif | |||
| #endif | |||
| } | |||
| #endif | |||
| #if defined(PNG_WRITE_sRGB_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_sRGB) | |||
| png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); | |||
| #endif | |||
| #if defined(PNG_WRITE_iCCP_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_iCCP) | |||
| png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, | |||
| info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); | |||
| #endif | |||
| #if defined(PNG_WRITE_sBIT_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_sBIT) | |||
| png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); | |||
| #endif | |||
| #if defined(PNG_WRITE_cHRM_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_cHRM) | |||
| { | |||
| #ifdef PNG_FLOATING_POINT_SUPPORTED | |||
| png_write_cHRM(png_ptr, | |||
| info_ptr->x_white, info_ptr->y_white, | |||
| info_ptr->x_red, info_ptr->y_red, | |||
| info_ptr->x_green, info_ptr->y_green, | |||
| info_ptr->x_blue, info_ptr->y_blue); | |||
| #else | |||
| # ifdef PNG_FIXED_POINT_SUPPORTED | |||
| png_write_cHRM_fixed(png_ptr, | |||
| info_ptr->int_x_white, info_ptr->int_y_white, | |||
| info_ptr->int_x_red, info_ptr->int_y_red, | |||
| info_ptr->int_x_green, info_ptr->int_y_green, | |||
| info_ptr->int_x_blue, info_ptr->int_y_blue); | |||
| # endif | |||
| #endif | |||
| } | |||
| #endif | |||
| #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) | |||
| if (info_ptr->unknown_chunks_num) | |||
| { | |||
| png_unknown_chunk *up; | |||
| png_debug(5, "writing extra chunks\n"); | |||
| for (up = info_ptr->unknown_chunks; | |||
| up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; | |||
| up++) | |||
| { | |||
| int keep=png_handle_as_unknown(png_ptr, up->name); | |||
| if (keep != HANDLE_CHUNK_NEVER && | |||
| up->location && (!(up->location & PNG_HAVE_PLTE)) && | |||
| ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || | |||
| (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) | |||
| { | |||
| png_write_chunk(png_ptr, up->name, up->data, up->size); | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; | |||
| } | |||
| } | |||
| void PNGAPI | |||
| png_write_info(png_structp png_ptr, png_infop info_ptr) | |||
| { | |||
| #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) | |||
| int i; | |||
| #endif | |||
| png_debug(1, "in png_write_info\n"); | |||
| png_write_info_before_PLTE(png_ptr, info_ptr); | |||
| if (info_ptr->valid & PNG_INFO_PLTE) | |||
| png_write_PLTE(png_ptr, info_ptr->palette, | |||
| (png_uint_32)info_ptr->num_palette); | |||
| else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) | |||
| png_error(png_ptr, "Valid palette required for paletted images\n"); | |||
| #if defined(PNG_WRITE_tRNS_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_tRNS) | |||
| { | |||
| #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) | |||
| /* invert the alpha channel (in tRNS) */ | |||
| if ((png_ptr->transformations & PNG_INVERT_ALPHA) && | |||
| info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) | |||
| { | |||
| int j; | |||
| for (j=0; j<(int)info_ptr->num_trans; j++) | |||
| info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]); | |||
| } | |||
| #endif | |||
| png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values), | |||
| info_ptr->num_trans, info_ptr->color_type); | |||
| } | |||
| #endif | |||
| #if defined(PNG_WRITE_bKGD_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_bKGD) | |||
| png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); | |||
| #endif | |||
| #if defined(PNG_WRITE_hIST_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_hIST) | |||
| png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); | |||
| #endif | |||
| #if defined(PNG_WRITE_oFFs_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_oFFs) | |||
| png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, | |||
| info_ptr->offset_unit_type); | |||
| #endif | |||
| #if defined(PNG_WRITE_pCAL_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_pCAL) | |||
| png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, | |||
| info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, | |||
| info_ptr->pcal_units, info_ptr->pcal_params); | |||
| #endif | |||
| #if defined(PNG_WRITE_sCAL_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_sCAL) | |||
| #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) | |||
| png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, | |||
| info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); | |||
| #else | |||
| #ifdef PNG_FIXED_POINT_SUPPORTED | |||
| png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, | |||
| info_ptr->scal_s_width, info_ptr->scal_s_height); | |||
| #else | |||
| png_warning(png_ptr, | |||
| "png_write_sCAL not supported; sCAL chunk not written.\n"); | |||
| #endif | |||
| #endif | |||
| #endif | |||
| #if defined(PNG_WRITE_pHYs_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_pHYs) | |||
| png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, | |||
| info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); | |||
| #endif | |||
| #if defined(PNG_WRITE_tIME_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_tIME) | |||
| { | |||
| png_write_tIME(png_ptr, &(info_ptr->mod_time)); | |||
| png_ptr->mode |= PNG_WROTE_tIME; | |||
| } | |||
| #endif | |||
| #if defined(PNG_WRITE_sPLT_SUPPORTED) | |||
| if (info_ptr->valid & PNG_INFO_sPLT) | |||
| for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) | |||
| png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); | |||
| #endif | |||
| #if defined(PNG_WRITE_TEXT_SUPPORTED) | |||
| /* Check to see if we need to write text chunks */ | |||
| for (i = 0; i < info_ptr->num_text; i++) | |||
| { | |||
| png_debug2(2, "Writing header text chunk %d, type %d\n", i, | |||
| info_ptr->text[i].compression); | |||
| /* an internationalized chunk? */ | |||
| if (info_ptr->text[i].compression > 0) | |||
| { | |||
| #if defined(PNG_WRITE_iTXt_SUPPORTED) | |||
| /* write international chunk */ | |||
| png_write_iTXt(png_ptr, | |||
| info_ptr->text[i].compression, | |||
| info_ptr->text[i].key, | |||
| info_ptr->text[i].lang, | |||
| info_ptr->text[i].lang_key, | |||
| info_ptr->text[i].text); | |||
| #else | |||
| png_warning(png_ptr, "Unable to write international text\n"); | |||
| #endif | |||
| /* Mark this chunk as written */ | |||
| info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; | |||
| } | |||
| /* If we want a compressed text chunk */ | |||
| else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) | |||
| { | |||
| #if defined(PNG_WRITE_zTXt_SUPPORTED) | |||
| /* write compressed chunk */ | |||
| png_write_zTXt(png_ptr, info_ptr->text[i].key, | |||
| info_ptr->text[i].text, 0, | |||
| info_ptr->text[i].compression); | |||
| #else | |||
| png_warning(png_ptr, "Unable to write compressed text\n"); | |||
| #endif | |||
| /* Mark this chunk as written */ | |||
| info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; | |||
| } | |||
| else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) | |||
| { | |||
| #if defined(PNG_WRITE_tEXt_SUPPORTED) | |||
| /* write uncompressed chunk */ | |||
| png_write_tEXt(png_ptr, info_ptr->text[i].key, | |||
| info_ptr->text[i].text, | |||
| 0); | |||
| #else | |||
| png_warning(png_ptr, "Unable to write uncompressed text\n"); | |||
| #endif | |||
| /* Mark this chunk as written */ | |||
| info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; | |||
| } | |||
| } | |||
| #endif | |||
| #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) | |||
| if (info_ptr->unknown_chunks_num) | |||
| { | |||
| png_unknown_chunk *up; | |||
| png_debug(5, "writing extra chunks\n"); | |||
| for (up = info_ptr->unknown_chunks; | |||
| up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; | |||
| up++) | |||
| { | |||
| int keep=png_handle_as_unknown(png_ptr, up->name); | |||
| if (keep != HANDLE_CHUNK_NEVER && | |||
| up->location && (up->location & PNG_HAVE_PLTE) && | |||
| !(up->location & PNG_HAVE_IDAT) && | |||
| ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || | |||
| (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) | |||
| { | |||
| png_write_chunk(png_ptr, up->name, up->data, up->size); | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| } | |||
| /* Writes the end of the PNG file. If you don't want to write comments or | |||
| * time information, you can pass NULL for info. If you already wrote these | |||
| * in png_write_info(), do not write them again here. If you have long | |||
| * comments, I suggest writing them here, and compressing them. | |||
| */ | |||
| void PNGAPI | |||
| png_write_end(png_structp png_ptr, png_infop info_ptr) | |||
| { | |||
| png_debug(1, "in png_write_end\n"); | |||
| if (!(png_ptr->mode & PNG_HAVE_IDAT)) | |||
| png_error(png_ptr, "No IDATs written into file"); | |||
| /* see if user wants us to write information chunks */ | |||
| if (info_ptr != NULL) | |||
| { | |||
| #if defined(PNG_WRITE_TEXT_SUPPORTED) | |||
| int i; /* local index variable */ | |||
| #endif | |||
| #if defined(PNG_WRITE_tIME_SUPPORTED) | |||
| /* check to see if user has supplied a time chunk */ | |||
| if ((info_ptr->valid & PNG_INFO_tIME) && | |||
| !(png_ptr->mode & PNG_WROTE_tIME)) | |||
| png_write_tIME(png_ptr, &(info_ptr->mod_time)); | |||
| #endif | |||
| #if defined(PNG_WRITE_TEXT_SUPPORTED) | |||
| /* loop through comment chunks */ | |||
| for (i = 0; i < info_ptr->num_text; i++) | |||
| { | |||
| png_debug2(2, "Writing trailer text chunk %d, type %d\n", i, | |||
| info_ptr->text[i].compression); | |||
| /* an internationalized chunk? */ | |||
| if (info_ptr->text[i].compression > 0) | |||
| { | |||
| #if defined(PNG_WRITE_iTXt_SUPPORTED) | |||
| /* write international chunk */ | |||
| png_write_iTXt(png_ptr, | |||
| info_ptr->text[i].compression, | |||
| info_ptr->text[i].key, | |||
| info_ptr->text[i].lang, | |||
| info_ptr->text[i].lang_key, | |||
| info_ptr->text[i].text); | |||
| #else | |||
| png_warning(png_ptr, "Unable to write international text\n"); | |||
| #endif | |||
| /* Mark this chunk as written */ | |||
| info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; | |||
| } | |||
| else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) | |||
| { | |||
| #if defined(PNG_WRITE_zTXt_SUPPORTED) | |||
| /* write compressed chunk */ | |||
| png_write_zTXt(png_ptr, info_ptr->text[i].key, | |||
| info_ptr->text[i].text, 0, | |||
| info_ptr->text[i].compression); | |||
| #else | |||
| png_warning(png_ptr, "Unable to write compressed text\n"); | |||
| #endif | |||
| /* Mark this chunk as written */ | |||
| info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; | |||
| } | |||
| else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) | |||
| { | |||
| #if defined(PNG_WRITE_tEXt_SUPPORTED) | |||
| /* write uncompressed chunk */ | |||
| png_write_tEXt(png_ptr, info_ptr->text[i].key, | |||
| info_ptr->text[i].text, 0); | |||
| #else | |||
| png_warning(png_ptr, "Unable to write uncompressed text\n"); | |||
| #endif | |||
| /* Mark this chunk as written */ | |||
| info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; | |||
| } | |||
| } | |||
| #endif | |||
| #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) | |||
| if (info_ptr->unknown_chunks_num) | |||
| { | |||
| png_unknown_chunk *up; | |||
| png_debug(5, "writing extra chunks\n"); | |||
| for (up = info_ptr->unknown_chunks; | |||
| up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; | |||
| up++) | |||
| { | |||
| int keep=png_handle_as_unknown(png_ptr, up->name); | |||
| if (keep != HANDLE_CHUNK_NEVER && | |||
| up->location && (up->location & PNG_AFTER_IDAT) && | |||
| ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || | |||
| (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) | |||
| { | |||
| png_write_chunk(png_ptr, up->name, up->data, up->size); | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| } | |||
| png_ptr->mode |= PNG_AFTER_IDAT; | |||
| /* write end of PNG file */ | |||
| png_write_IEND(png_ptr); | |||
| #if 0 | |||
| /* This flush, added in libpng-1.0.8, causes some applications to crash | |||
| because they do not set png_ptr->output_flush_fn */ | |||
| png_flush(png_ptr); | |||
| #endif | |||
| } | |||
| #if defined(PNG_WRITE_tIME_SUPPORTED) | |||
| #if !defined(_WIN32_WCE) | |||
| /* "time.h" functions are not supported on WindowsCE */ | |||
| void PNGAPI | |||
| png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) | |||
| { | |||
| png_debug(1, "in png_convert_from_struct_tm\n"); | |||
| ptime->year = (png_uint_16)(1900 + ttime->tm_year); | |||
| ptime->month = (png_byte)(ttime->tm_mon + 1); | |||
| ptime->day = (png_byte)ttime->tm_mday; | |||
| ptime->hour = (png_byte)ttime->tm_hour; | |||
| ptime->minute = (png_byte)ttime->tm_min; | |||
| ptime->second = (png_byte)ttime->tm_sec; | |||
| } | |||
| void PNGAPI | |||
| png_convert_from_time_t(png_timep ptime, time_t ttime) | |||
| { | |||
| struct tm *tbuf; | |||
| png_debug(1, "in png_convert_from_time_t\n"); | |||
| tbuf = gmtime(&ttime); | |||
| png_convert_from_struct_tm(ptime, tbuf); | |||
| } | |||
| #endif | |||
| #endif | |||
| /* called by user to write a row of image data */ | |||
| void PNGAPI | |||
| png_write_row(png_structp png_ptr, png_bytep row) | |||
| { | |||
| png_debug2(1, "in png_write_row (row %ld, pass %d)\n", | |||
| png_ptr->row_number, png_ptr->pass); | |||
| /* initialize transformations and other stuff if first time */ | |||
| if (png_ptr->row_number == 0 && png_ptr->pass == 0) | |||
| { | |||
| /* make sure we wrote the header info */ | |||
| if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) | |||
| png_error(png_ptr, | |||
| "png_write_info was never called before png_write_row."); | |||
| /* check for transforms that have been set but were defined out */ | |||
| #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_INVERT_MONO) | |||
| png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined."); | |||
| #endif | |||
| #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_FILLER) | |||
| png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined."); | |||
| #endif | |||
| #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_PACKSWAP) | |||
| png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined."); | |||
| #endif | |||
| #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_PACK) | |||
| png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined."); | |||
| #endif | |||
| #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_SHIFT) | |||
| png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined."); | |||
| #endif | |||
| #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_BGR) | |||
| png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined."); | |||
| #endif | |||
| #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) | |||
| if (png_ptr->transformations & PNG_SWAP_BYTES) | |||
| png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined."); | |||
| #endif | |||
| png_write_start_row(png_ptr); | |||
| } | |||
| #if defined(PNG_WRITE_INTERLACING_SUPPORTED) | |||
| /* if interlaced and not interested in row, return */ | |||
| if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) | |||
| { | |||
| switch (png_ptr->pass) | |||
| { | |||
| case 0: | |||
| if (png_ptr->row_number & 0x07) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 1: | |||
| if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 2: | |||
| if ((png_ptr->row_number & 0x07) != 4) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 3: | |||
| if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 4: | |||
| if ((png_ptr->row_number & 0x03) != 2) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 5: | |||
| if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| case 6: | |||
| if (!(png_ptr->row_number & 0x01)) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| #endif | |||
| /* set up row info for transformations */ | |||
| png_ptr->row_info.color_type = png_ptr->color_type; | |||
| png_ptr->row_info.width = png_ptr->usr_width; | |||
| png_ptr->row_info.channels = png_ptr->usr_channels; | |||
| png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; | |||
| png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * | |||
| png_ptr->row_info.channels); | |||
| png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * | |||
| (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); | |||
| png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type); | |||
| png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width); | |||
| png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels); | |||
| png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth); | |||
| png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth); | |||
| png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes); | |||
| /* Copy user's row into buffer, leaving room for filter byte. */ | |||
| png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row, | |||
| png_ptr->row_info.rowbytes); | |||
| #if defined(PNG_WRITE_INTERLACING_SUPPORTED) | |||
| /* handle interlacing */ | |||
| if (png_ptr->interlaced && png_ptr->pass < 6 && | |||
| (png_ptr->transformations & PNG_INTERLACE)) | |||
| { | |||
| png_do_write_interlace(&(png_ptr->row_info), | |||
| png_ptr->row_buf + 1, png_ptr->pass); | |||
| /* this should always get caught above, but still ... */ | |||
| if (!(png_ptr->row_info.width)) | |||
| { | |||
| png_write_finish_row(png_ptr); | |||
| return; | |||
| } | |||
| } | |||
| #endif | |||
| #if 0 | |||
| /* handle other transformations */ | |||
| if (png_ptr->transformations) | |||
| png_do_write_transformations(png_ptr); | |||
| #endif | |||
| #if defined(PNG_MNG_FEATURES_SUPPORTED) | |||
| /* Write filter_method 64 (intrapixel differencing) only if | |||
| * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and | |||
| * 2. Libpng did not write a PNG signature (this filter_method is only | |||
| * used in PNG datastreams that are embedded in MNG datastreams) and | |||
| * 3. The application called png_permit_mng_features with a mask that | |||
| * included PNG_FLAG_MNG_FILTER_64 and | |||
| * 4. The filter_method is 64 and | |||
| * 5. The color_type is RGB or RGBA | |||
| */ | |||
| if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && | |||
| (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) | |||
| { | |||
| /* Intrapixel differencing */ | |||
| png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); | |||
| } | |||
| #endif | |||
| /* Find a filter if necessary, filter the row and write it out. */ | |||
| png_write_find_filter(png_ptr, &(png_ptr->row_info)); | |||
| if (png_ptr->write_row_fn != NULL) | |||
| (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); | |||
| } | |||
| /* Free any memory used in png_ptr struct (old method) */ | |||
| void /* PRIVATE */ | |||
| png_write_destroy(png_structp png_ptr) | |||
| { | |||
| #ifdef PNG_SETJMP_SUPPORTED | |||
| jmp_buf tmp_jmp; /* save jump buffer */ | |||
| #endif | |||
| #ifdef PNG_USER_MEM_SUPPORTED | |||
| png_free_ptr free_fn; | |||
| #endif | |||
| png_debug(1, "in png_write_destroy\n"); | |||
| /* free any memory zlib uses */ | |||
| deflateEnd(&png_ptr->zstream); | |||
| /* free our memory. png_free checks NULL for us. */ | |||
| png_free(png_ptr, png_ptr->zbuf); | |||
| png_free(png_ptr, png_ptr->row_buf); | |||
| png_free(png_ptr, png_ptr->prev_row); | |||
| png_free(png_ptr, png_ptr->sub_row); | |||
| png_free(png_ptr, png_ptr->up_row); | |||
| png_free(png_ptr, png_ptr->avg_row); | |||
| png_free(png_ptr, png_ptr->paeth_row); | |||
| #if defined(PNG_TIME_RFC1123_SUPPORTED) | |||
| png_free(png_ptr, png_ptr->time_buffer); | |||
| #endif | |||
| #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) | |||
| png_free(png_ptr, png_ptr->prev_filters); | |||
| png_free(png_ptr, png_ptr->filter_weights); | |||
| png_free(png_ptr, png_ptr->inv_filter_weights); | |||
| png_free(png_ptr, png_ptr->filter_costs); | |||
| png_free(png_ptr, png_ptr->inv_filter_costs); | |||
| #endif | |||
| #ifdef PNG_SETJMP_SUPPORTED | |||
| /* reset structure */ | |||
| png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); | |||
| #endif | |||
| #ifdef PNG_USER_MEM_SUPPORTED | |||
| free_fn = png_ptr->free_fn; | |||
| #endif | |||
| png_memset(png_ptr, 0, sizeof (png_struct)); | |||
| #ifdef PNG_USER_MEM_SUPPORTED | |||
| png_ptr->free_fn = free_fn; | |||
| #endif | |||
| #ifdef PNG_SETJMP_SUPPORTED | |||
| png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); | |||
| #endif | |||
| } | |||
| /* Allow the application to select one or more row filters to use. */ | |||
| void PNGAPI | |||
| png_set_filter(png_structp png_ptr, int method, int filters) | |||
| { | |||
| png_debug(1, "in png_set_filter\n"); | |||
| #if defined(PNG_MNG_FEATURES_SUPPORTED) | |||
| if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && | |||
| (method == PNG_INTRAPIXEL_DIFFERENCING)) | |||
| method = PNG_FILTER_TYPE_BASE; | |||
| #endif | |||
| if (method == PNG_FILTER_TYPE_BASE) | |||
| { | |||
| switch (filters & (PNG_ALL_FILTERS | 0x07)) | |||
| { | |||
| case 5: | |||
| case 6: | |||
| case 7: png_warning(png_ptr, "Unknown row filter for method 0"); | |||
| case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break; | |||
| case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break; | |||
| case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break; | |||
| case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break; | |||
| case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break; | |||
| default: png_ptr->do_filter = (png_byte)filters; break; | |||
| } | |||
| /* If we have allocated the row_buf, this means we have already started | |||
| * with the image and we should have allocated all of the filter buffers | |||
| * that have been selected. If prev_row isn't already allocated, then | |||
| * it is too late to start using the filters that need it, since we | |||
| * will be missing the data in the previous row. If an application | |||
| * wants to start and stop using particular filters during compression, | |||
| * it should start out with all of the filters, and then add and | |||
| * remove them after the start of compression. | |||
| */ | |||
| if (png_ptr->row_buf != NULL) | |||
| { | |||
| if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) | |||
| { | |||
| png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, | |||
| (png_ptr->rowbytes + 1)); | |||
| png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; | |||
| } | |||
| if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) | |||
| { | |||
| if (png_ptr->prev_row == NULL) | |||
| { | |||
| png_warning(png_ptr, "Can't add Up filter after starting"); | |||
| png_ptr->do_filter &= ~PNG_FILTER_UP; | |||
| } | |||
| else | |||
| { | |||
| png_ptr->up_row = (png_bytep)png_malloc(png_ptr, | |||
| (png_ptr->rowbytes + 1)); | |||
| png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; | |||
| } | |||
| } | |||
| if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) | |||
| { | |||
| if (png_ptr->prev_row == NULL) | |||
| { | |||
| png_warning(png_ptr, "Can't add Average filter after starting"); | |||
| png_ptr->do_filter &= ~PNG_FILTER_AVG; | |||
| } | |||
| else | |||
| { | |||
| png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, | |||
| (png_ptr->rowbytes + 1)); | |||
| png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; | |||
| } | |||
| } | |||
| if ((png_ptr->do_filter & PNG_FILTER_PAETH) && | |||
| png_ptr->paeth_row == NULL) | |||
| { | |||
| if (png_ptr->prev_row == NULL) | |||
| { | |||
| png_warning(png_ptr, "Can't add Paeth filter after starting"); | |||
| png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); | |||
| } | |||
| else | |||
| { | |||
| png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, | |||
| (png_ptr->rowbytes + 1)); | |||
| png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; | |||
| } | |||
| } | |||
| if (png_ptr->do_filter == PNG_NO_FILTERS) | |||
| png_ptr->do_filter = PNG_FILTER_NONE; | |||
| } | |||
| } | |||
| else | |||
| png_error(png_ptr, "Unknown custom filter method"); | |||
| } | |||
| /* This allows us to influence the way in which libpng chooses the "best" | |||
| * filter for the current scanline. While the "minimum-sum-of-absolute- | |||
| * differences metric is relatively fast and effective, there is some | |||
| * question as to whether it can be improved upon by trying to keep the | |||
| * filtered data going to zlib more consistent, hopefully resulting in | |||
| * better compression. | |||
| */ | |||
| #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */ | |||
| void PNGAPI | |||
| png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, | |||
| int num_weights, png_doublep filter_weights, | |||
| png_doublep filter_costs) | |||
| { | |||
| int i; | |||
| png_debug(1, "in png_set_filter_heuristics\n"); | |||
| if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) | |||
| { | |||
| png_warning(png_ptr, "Unknown filter heuristic method"); | |||
| return; | |||
| } | |||
| if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) | |||
| { | |||
| heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; | |||
| } | |||
| if (num_weights < 0 || filter_weights == NULL || | |||
| heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) | |||
| { | |||
| num_weights = 0; | |||
| } | |||
| png_ptr->num_prev_filters = (png_byte)num_weights; | |||
| png_ptr->heuristic_method = (png_byte)heuristic_method; | |||
| if (num_weights > 0) | |||
| { | |||
| if (png_ptr->prev_filters == NULL) | |||
| { | |||
| png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, | |||
| (png_uint_32)(sizeof(png_byte) * num_weights)); | |||
| /* To make sure that the weighting starts out fairly */ | |||
| for (i = 0; i < num_weights; i++) | |||
| { | |||
| png_ptr->prev_filters[i] = 255; | |||
| } | |||
| } | |||
| if (png_ptr->filter_weights == NULL) | |||
| { | |||
| png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, | |||
| (png_uint_32)(sizeof(png_uint_16) * num_weights)); | |||
| png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, | |||
| (png_uint_32)(sizeof(png_uint_16) * num_weights)); | |||
| for (i = 0; i < num_weights; i++) | |||
| { | |||
| png_ptr->inv_filter_weights[i] = | |||
| png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; | |||
| } | |||
| } | |||
| for (i = 0; i < num_weights; i++) | |||
| { | |||
| if (filter_weights[i] < 0.0) | |||
| { | |||
| png_ptr->inv_filter_weights[i] = | |||
| png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; | |||
| } | |||
| else | |||
| { | |||
| png_ptr->inv_filter_weights[i] = | |||
| (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); | |||
| png_ptr->filter_weights[i] = | |||
| (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); | |||
| } | |||
| } | |||
| } | |||
| /* If, in the future, there are other filter methods, this would | |||
| * need to be based on png_ptr->filter. | |||
| */ | |||
| if (png_ptr->filter_costs == NULL) | |||
| { | |||
| png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, | |||
| (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); | |||
| png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, | |||
| (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); | |||
| for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) | |||
| { | |||
| png_ptr->inv_filter_costs[i] = | |||
| png_ptr->filter_costs[i] = PNG_COST_FACTOR; | |||
| } | |||
| } | |||
| /* Here is where we set the relative costs of the different filters. We | |||
| * should take the desired compression level into account when setting | |||
| * the costs, so that Paeth, for instance, has a high relative cost at low | |||
| * compression levels, while it has a lower relative cost at higher | |||
| * compression settings. The filter types are in order of increasing | |||
| * relative cost, so it would be possible to do this with an algorithm. | |||
| */ | |||
| for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) | |||
| { | |||
| if (filter_costs == NULL || filter_costs[i] < 0.0) | |||
| { | |||
| png_ptr->inv_filter_costs[i] = | |||
| png_ptr->filter_costs[i] = PNG_COST_FACTOR; | |||
| } | |||
| else if (filter_costs[i] >= 1.0) | |||
| { | |||
| png_ptr->inv_filter_costs[i] = | |||
| (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); | |||
| png_ptr->filter_costs[i] = | |||
| (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); | |||
| } | |||
| } | |||
| } | |||
| #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ | |||
| void PNGAPI | |||
| png_set_compression_level(png_structp png_ptr, int level) | |||
| { | |||
| png_debug(1, "in png_set_compression_level\n"); | |||
| png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; | |||
| png_ptr->zlib_level = level; | |||
| } | |||
| void PNGAPI | |||
| png_set_compression_mem_level(png_structp png_ptr, int mem_level) | |||
| { | |||
| png_debug(1, "in png_set_compression_mem_level\n"); | |||
| png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; | |||
| png_ptr->zlib_mem_level = mem_level; | |||
| } | |||
| void PNGAPI | |||
| png_set_compression_strategy(png_structp png_ptr, int strategy) | |||
| { | |||
| png_debug(1, "in png_set_compression_strategy\n"); | |||
| png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; | |||
| png_ptr->zlib_strategy = strategy; | |||
| } | |||
| void PNGAPI | |||
| png_set_compression_window_bits(png_structp png_ptr, int window_bits) | |||
| { | |||
| if (window_bits > 15) | |||
| png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); | |||
| else if (window_bits < 8) | |||
| png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); | |||
| #ifndef WBITS_8_OK | |||
| /* avoid libpng bug with 256-byte windows */ | |||
| if (window_bits == 8) | |||
| { | |||
| png_warning(png_ptr, "Compression window is being reset to 512"); | |||
| window_bits=9; | |||
| } | |||
| #endif | |||
| png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; | |||
| png_ptr->zlib_window_bits = window_bits; | |||
| } | |||
| void PNGAPI | |||
| png_set_compression_method(png_structp png_ptr, int method) | |||
| { | |||
| png_debug(1, "in png_set_compression_method\n"); | |||
| if (method != 8) | |||
| png_warning(png_ptr, "Only compression method 8 is supported by PNG"); | |||
| png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; | |||
| png_ptr->zlib_method = method; | |||
| } | |||
| #endif /* PNG_WRITE_SUPPORTED */ | |||