/* 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 == NULL || info_ptr == NULL) return; 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"); 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 != PNG_HANDLE_CHUNK_NEVER && up->location && !(up->location & PNG_HAVE_PLTE) && !(up->location & PNG_HAVE_IDAT) && ((up->name[3] & 0x20) || keep == PNG_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; }
/* 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 png_write_info(png_structp png_ptr, png_infop info_ptr) { #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) int i; #endif png_debug(1, "in png_write_info\n"); png_write_sig(png_ptr); /* write PNG signature */ /* 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) png_write_gAMA(png_ptr, info_ptr->gamma); #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_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) 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); #endif 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] = 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_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->flags |= PNG_FLAG_WROTE_tIME; } #endif #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_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); /* If we want a compressed text chunk */ 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, info_ptr->text[i].text_length, 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, info_ptr->text[i].text_length); #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 }
/* * Copies a PNG file stream to another PNG file stream. */ int opng_copy_png(struct opng_codec_context *context, FILE *in_stream, const char *Infile, FILE *out_stream, const char *Outfile) { volatile png_bytep buf; /* volatile is required by cexcept */ const png_uint_32 buf_size_incr = 4096; png_uint_32 length; png_byte chunk_hdr[8]; const char * volatile err_msg; int volatile result = 0; context->libpng_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, opng_write_error, opng_write_warning); if (!context->libpng_ptr) { opng_error(0, "Out of memory"); exit(1); } struct opng_encoding_stats * stats = context->stats; opng_init_stats(stats); context->stream = out_stream; context->fname = Outfile; png_set_write_fn(context->libpng_ptr, context, opng_write_data, 0); Try { buf = 0; png_uint_32 buf_size = 0; /* Write the signature in the output file. */ png_write_sig(context->libpng_ptr); /* Copy all chunks until IEND. */ /* Error checking is done only at a very basic level. */ do { if (fread(chunk_hdr, 8, 1, in_stream) != 1) /* length + name */ { opng_error(Infile, "Read error"); result = -1; break; } length = png_get_uint_32(chunk_hdr); if (length > PNG_UINT_31_MAX) { if (!buf && length == 0x89504e47UL) /* "\x89PNG" */ continue; /* skip the signature */ opng_error(Infile, "Data error"); result = -1; break; } if (length + 4 > buf_size) { png_free(context->libpng_ptr, buf); buf_size = (((length + 4) + (buf_size_incr - 1)) / buf_size_incr) * buf_size_incr; buf = (png_bytep)png_malloc(context->libpng_ptr, buf_size); if (!buf) { exit(1); } /* Do not use realloc() here, it's unnecessarily slow. */ } if (fread(buf, length + 4, 1, in_stream) != 1) /* data + crc */ { opng_error(Infile, "Read error"); result = -1; break; } png_write_chunk(context->libpng_ptr, chunk_hdr + 4, buf, length); } while (memcmp(chunk_hdr + 4, opng_sig_IEND, 4) != 0); } Catch (err_msg) { opng_error(Outfile, err_msg); result = -1; } png_free(context->libpng_ptr, buf); png_destroy_write_struct(&context->libpng_ptr, 0); return result; }
static uint8_t png_write( png_structp writePtr, png_image * image, uint32_t flags ) { const uint32_t h = image->height; const uint32_t w = image->width; const uint8_t * p = image->data; const uint32_t bitDepth = 8; const uint32_t channels = 4; png_infop infoPtr = png_create_info_struct( writePtr ); if (!infoPtr) { pngio_error( "Couldn't initialize PNG info struct" ); png_destroy_write_struct( & writePtr, NULL ); return 0; } if (setjmp( png_jmpbuf( writePtr ) )) { png_destroy_write_struct( & writePtr, & infoPtr ); pngio_error( "An error occured while writing the PNG file." ); return 0; } png_set_filter( writePtr, 0, PNG_FILTER_NONE ); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_write_sig( writePtr ); png_set_sig_bytes( writePtr, 8 ); png_set_compression_window_bits( writePtr, -15 ); png_set_write_user_transform_fn( writePtr, png_write_swap_and_premultiply_transform ); png_set_user_transform_info( writePtr, NULL, bitDepth, channels ); } #endif png_set_IHDR( writePtr, infoPtr, w, h, bitDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_set_gAMA( writePtr, infoPtr, 0.45455 ); png_set_cHRM( writePtr, infoPtr, 0.312700, 0.329, 0.64, 0.33, 0.3, 0.6, 0.15, 0.06 ); png_set_sRGB( writePtr, infoPtr, 0); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_byte cname[] = { 'C', 'g', 'B', 'I', '\0' }; png_byte cdata[] = { 0x50, 0x00, 0x20, 0x02 }; png_write_chunk( writePtr, cname, cdata, 4 ); } #endif png_write_info( writePtr, infoPtr ); const size_t bytesPerRow = w * 4; if (flags & PNG_IMAGE_FLIP_VERTICAL) { for (size_t i = 0; i < h; i++) { png_write_row( writePtr, p + (bytesPerRow * (h - i - 1)) ); } } else { for (size_t i = 0; i < h; i++) { png_write_row( writePtr, p + (bytesPerRow * i) ); } } png_write_end( writePtr, infoPtr ); png_destroy_write_struct( & writePtr, & infoPtr ); return 1; }