/* Initialize png_ptr structure, and allocate any memory needed */ png_structp png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn) { #ifdef PNG_USER_MEM_SUPPORTED return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, warn_fn, NULL, NULL, NULL)); }
static int png_save(BPGDecoderContext *img, mem_encode * mempng, int bit_depth) { BPGImageInfo img_info_s, *img_info = &img_info_s; FILE *f; png_structp png_ptr; png_infop info_ptr; png_bytep row_pointer; int y, color_type, bpp; BPGDecoderOutputFormat out_fmt; mempng->buffer = 0; mempng->size = 0; if (bit_depth != 8 && bit_depth != 16) { fprintf(stderr, "Only bit_depth = 8 or 16 are supported for PNG output\n"); return -1; } bpg_decoder_get_info(img, img_info); png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, /* error */ NULL, /* warning */ NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); png_set_write_fn(png_ptr, (png_voidp)mempng, &png_write_data_buffer, NULL); if (setjmp(png_jmpbuf(png_ptr)) != 0) { fprintf(stderr, "PNG write error\n"); return -1; } if (img_info->has_alpha) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, img_info->width, img_info->height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); #if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ if (bit_depth == 16) { png_set_swap(png_ptr); } #endif if (bit_depth == 16) { if (img_info->has_alpha) out_fmt = BPG_OUTPUT_FORMAT_RGBA64; else out_fmt = BPG_OUTPUT_FORMAT_RGB48; } else { if (img_info->has_alpha) out_fmt = BPG_OUTPUT_FORMAT_RGBA32; else out_fmt = BPG_OUTPUT_FORMAT_RGB24; } bpg_decoder_start(img, out_fmt); bpp = (3 + img_info->has_alpha) * (bit_depth / 8); row_pointer = (png_bytep)png_malloc(png_ptr, img_info->width * bpp); for (y = 0; y < img_info->height; y++) { bpg_decoder_get_line(img, row_pointer); png_write_row(png_ptr, row_pointer); } png_free(png_ptr, row_pointer); png_write_end(png_ptr, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; }
/* Test one file */ int test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) { static png_FILE_p fpin; static png_FILE_p fpout; /* "static" prevents setjmp corruption */ png_structp read_ptr; png_infop read_info_ptr, end_info_ptr; #ifdef PNG_WRITE_SUPPORTED png_structp write_ptr; png_infop write_info_ptr; png_infop write_end_info_ptr; #else png_structp write_ptr = NULL; png_infop write_info_ptr = NULL; png_infop write_end_info_ptr = NULL; #endif png_bytep row_buf; png_uint_32 y; png_uint_32 width, height; int num_pass, pass; int bit_depth, color_type; #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmpbuf; #endif #endif #if defined(_WIN32_WCE) TCHAR path[MAX_PATH]; #endif char inbuf[256], outbuf[256]; row_buf = NULL; #if defined(_WIN32_WCE) MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) #else if ((fpin = fopen(inname, "rb")) == NULL) #endif { fprintf(STDERR, "Could not find input file %s\n", inname); return (1); } #if defined(_WIN32_WCE) MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) #else if ((fpout = fopen(outname, "wb")) == NULL) #endif { fprintf(STDERR, "Could not open output file %s\n", outname); FCLOSE(fpin); return (1); } png_debug(0, "Allocating read and write structures\n"); #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); #else read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL); #endif #if defined(PNG_NO_STDIO) png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, pngtest_warning); #endif #ifdef PNG_WRITE_SUPPORTED #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); #else write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL); #endif #if defined(PNG_NO_STDIO) png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, pngtest_warning); #endif #endif png_debug(0, "Allocating read_info, write_info and end_info structures\n"); read_info_ptr = png_create_info_struct(read_ptr); end_info_ptr = png_create_info_struct(read_ptr); #ifdef PNG_WRITE_SUPPORTED write_info_ptr = png_create_info_struct(write_ptr); write_end_info_ptr = png_create_info_struct(write_ptr); #endif #ifdef PNG_SETJMP_SUPPORTED png_debug(0, "Setting jmpbuf for read struct\n"); #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) #else if (setjmp(png_jmpbuf(read_ptr))) #endif { fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); if (row_buf) png_free(read_ptr, row_buf); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); #ifdef PNG_WRITE_SUPPORTED png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr); #endif FCLOSE(fpin); FCLOSE(fpout); return (1); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(read_ptr),jmpbuf,png_sizeof(jmp_buf)); #endif #ifdef PNG_WRITE_SUPPORTED png_debug(0, "Setting jmpbuf for write struct\n"); #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) #else if (setjmp(png_jmpbuf(write_ptr))) #endif { fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); png_destroy_info_struct(write_ptr, &write_end_info_ptr); #ifdef PNG_WRITE_SUPPORTED png_destroy_write_struct(&write_ptr, &write_info_ptr); #endif FCLOSE(fpin); FCLOSE(fpout); return (1); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(write_ptr),jmpbuf,png_sizeof(jmp_buf)); #endif #endif #endif png_debug(0, "Initializing input and output streams\n"); #if !defined(PNG_NO_STDIO) png_init_io(read_ptr, fpin); # ifdef PNG_WRITE_SUPPORTED png_init_io(write_ptr, fpout); # endif #else png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); # ifdef PNG_WRITE_SUPPORTED png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, # if defined(PNG_WRITE_FLUSH_SUPPORTED) pngtest_flush); # else NULL); # endif # endif #endif if(status_dots_requested == 1) { #ifdef PNG_WRITE_SUPPORTED png_set_write_status_fn(write_ptr, write_row_callback); #endif png_set_read_status_fn(read_ptr, read_row_callback); } else { #ifdef PNG_WRITE_SUPPORTED png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL); #endif png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); } #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) { int i; for(i=0; i<256; i++) filters_used[i]=0; png_set_read_user_transform_fn(read_ptr, count_filters); } #endif #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) zero_samples=0; png_set_write_user_transform_fn(write_ptr, count_zero_samples); #endif #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) # ifndef PNG_HANDLE_CHUNK_ALWAYS # define PNG_HANDLE_CHUNK_ALWAYS 3 # endif png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, png_bytep_NULL, 0); #endif #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) # ifndef PNG_HANDLE_CHUNK_IF_SAFE # define PNG_HANDLE_CHUNK_IF_SAFE 2 # endif png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, png_bytep_NULL, 0); #endif png_debug(0, "Reading info struct\n"); png_read_info(read_ptr, read_info_ptr); png_debug(0, "Transferring info struct\n"); { int interlace_type, compression_type, filter_type; if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type)) { png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, #if defined(PNG_WRITE_INTERLACING_SUPPORTED) color_type, interlace_type, compression_type, filter_type); #else color_type, PNG_INTERLACE_NONE, compression_type, filter_type); #endif } }
BOOL OutputPNG::OutputPNGHeader(CCLexFile *File, LPBITMAPINFOHEADER pInfo, BOOL InterlaceState, INT32 TransparentColour, LPLOGPALETTE pPalette, LPRGBQUAD pQuadPalette) { ERROR2IF(File==NULL,FALSE,"OutputPNG::OutputPNGHeader File pointer is null"); if (pInfo == NULL) pInfo = &(DestBitmapInfo->bmiHeader); ERROR2IF(pInfo==NULL,FALSE,"OutputPNG::OutputPNGHeader BitmapInfo pointer is null"); //ERROR2IF(pPalette==NULL && pQuadPalette==NULL,FALSE,"OutputPNG::OutputPNGHeader Bitmap palette pointer is null"); TRACEUSER( "Jonathan", _T("PNG write: Interlace: %s\n"), InterlaceState ? _T("Yes") : _T("No")); // Note file in our class variable as used by all the low level routines OutputFile = File; // Note the specified transparency and interlace states in our class variables Interlace = InterlaceState; if (TransparentColour != -1) Transparent = TRUE; else Transparent = FALSE; // We are just about to start so set the PNG exception handling up with our CCFile pointer PNGUtil::SetCCFilePointer(File); // Must set the exception throwing flag to True and force reporting of errors to False. // This means that the caller must report an error if the function returns False. // Any calls to CCFile::GotError will now throw a file exception and should fall into // the catch handler at the end of the function. // Replaces the goto's that handled this before. BOOL OldThrowingState = File->SetThrowExceptions( TRUE ); BOOL OldReportingState = File->SetReportErrors( FALSE ); // PNG related items (NOTE: p at end means pointer and hence implied *) png_ptr = NULL; info_ptr = NULL; palette = NULL; try { // Work out the palette size INT32 PalSize = pInfo->biClrUsed; // How many entries in palette TRACEUSER( "Jonathan", _T("PNG write: PalSize = %d\n"),PalSize); // Set up the class variables // First the width/height of the bitmap Width = pInfo->biWidth; Height = pInfo->biHeight; TRACEUSER( "Jonathan", _T("PNG write: Width = %d Height = %d\n"),Width,Height); BitsPerPixel = pInfo->biBitCount; // Start up the PNG writing code // allocate the necessary structures // Use the default handlers png_ptr = png_create_write_struct_2( PNG_LIBPNG_VER_STRING, // libpng version 0, // Optional pointer to be sent with errors camelot_png_error, // Function called in case of error camelot_png_warning, // Function called for warnings 0, // Optional pointer to be sent with mem ops camelot_png_malloc, // Function called to alloc memory camelot_png_free // Function called to free memory ); if (!png_ptr) File->GotError( _R(IDS_OUT_OF_MEMORY) ); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); File->GotError( _R(IDS_OUT_OF_MEMORY) ); } // set up the input control to the fstream class // If not a disk file then panic for the present moment // Could use the memfile functions for reading and writing as they give us what // we want. Use the io_ptr and iostream* pFStream = File->GetIOFile(); if (pFStream == NULL) { TRACEUSER( "Jonathan", _T("PNG write: OutputPNG::OutputPNGHeader No access to IOStream!")); File->GotError( _R(IDS_UNKNOWN_PNG_ERROR) ); } // Should use our own function png_set_write_fn(png_ptr, pFStream, camelot_png_write_data, camelot_png_flush_data); // png_init_io(png_ptr, pFStream); // You now have the option of modifying how the compression library // will run. The following functions are mainly for testing, but // may be useful in certain special cases, like if you need to // write png files extremely fast and are willing to give up some // compression, or if you want to get the maximum possible compression // at the expense of slower writing. If you have no special needs // in this area, let the library do what it wants, as it has been // carefully tuned to deliver the best speed/compression ratio. // See the compression library for more details. // turn on or off filtering (1 or 0) //png_set_filtering(png_ptr, 1); // compression level (0 - none, 6 - default, 9 - maximum) //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); //png_set_compression_mem_level(png_ptr, 8); //png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); //png_set_compression_window_bits(png_ptr, 15); //png_set_compression_method(png_ptr, 8); // - this describes which optional chunks to write to the // file. Note that if you are writing a // PNG_COLOR_TYPE_PALETTE file, the PLTE chunk is not // optional, but must still be marked for writing. To // mark chunks for writing, OR valid with the // appropriate PNG_INFO_<chunk name> define. png_get_valid(png_ptr, info_ptr, 0); // resolution of image png_set_invalid(png_ptr, info_ptr, PNG_INFO_pHYs); png_set_pHYs(png_ptr, info_ptr, pInfo->biXPelsPerMeter, pInfo->biYPelsPerMeter, 1); //meter TRACEUSER( "Jonathan", _T("PNG write: x,y px per cm = %d %d\n"), png_get_x_pixels_per_meter(png_ptr, info_ptr) / 1000, png_get_y_pixels_per_meter(png_ptr, info_ptr) / 1000); BitsPerPixel = pInfo->biBitCount; TRACEUSER( "Jonathan", _T("PNG write: Bitdepth = %d\n"), BitsPerPixel); palette = NULL; num_palette = 0; trans = NULL; // - array of transparent entries for paletted images num_trans = 0; // - number of transparent entries TRACEUSER( "Jonathan", _T("PNG write: TransColour = %d\n"), TransparentColour); if ( BitsPerPixel <= 8 ) { png_set_IHDR(png_ptr, info_ptr, Width, Height, BitsPerPixel, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set the palette if there is one png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE); INT32 PaletteEntries = pInfo->biClrUsed; palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); if (palette == NULL) File->GotError( _R(IDS_OUT_OF_MEMORY) ); png_set_PLTE(png_ptr, info_ptr, palette, num_palette); png_color_struct * pPNGPalette = palette; // ... set palette colors ... if (pQuadPalette && PaletteEntries > 0) { // Palette supplied in RGBQUAD form for (INT32 i = 0; i < PaletteEntries; i++) { pPNGPalette->red = pQuadPalette->rgbRed; pPNGPalette->green = pQuadPalette->rgbGreen; pPNGPalette->blue = pQuadPalette->rgbBlue; // skip to the next palette entry pQuadPalette++; pPNGPalette++; } } else if (pPalette && PaletteEntries > 0) { // Palette supplied in LOGPALETTE form for (INT32 i = 0; i < PaletteEntries; i++) { pPNGPalette->red = pPalette->palPalEntry[i].peRed; pPNGPalette->green = pPalette->palPalEntry[i].peGreen; pPNGPalette->blue = pPalette->palPalEntry[i].peBlue; pPNGPalette++; } } else File->GotError(_R(IDS_PNG_ERR_WRITE_PALETTE)); // Now check to see if transparency is present or not if (TransparentColour >= 0 && TransparentColour <= PaletteEntries ) { // Create the array of transparent entries for this palette // 0 is fully transparent, 255 is fully opaque, regardless of image bit depth // We will only create as many as we require, i.e. up to the transparent colour entry // rather a full palettes worth INT32 NumEntries = TransparentColour + 1; trans = (png_byte*)png_malloc(png_ptr, NumEntries * sizeof (png_byte)); if (trans) { // Set the number of transparent entries num_trans = NumEntries; png_byte * pTransEntry = trans; png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS); for (INT32 i = 0; i < TransparentColour; i++) { *pTransEntry = 255; // set it fully opaque pTransEntry++; } // We should now be at the transparent entry so set it fully transparent *pTransEntry = 0; } } } else if (BitsPerPixel == 24) { png_set_IHDR(png_ptr, info_ptr, Width, Height, 8, /* bit_depth */ PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } else if (BitsPerPixel == 32) { png_set_IHDR(png_ptr, info_ptr, Width, Height, 8, /* bit_depth */ PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } else ERROR2(FALSE,"OutputPNG::OutputPNGHeader Unknown bit depth"); TRACEUSER( "Jonathan", _T("PNG write: bit_depth = %d color_type = %d\n"), png_get_bit_depth(png_ptr, info_ptr), png_get_color_type(png_ptr, info_ptr)); // Could use:- // if we are dealing with a grayscale image then //info_ptr->sig_bit.gray = true_bit_depth; png_set_hIST(png_ptr, info_ptr, NULL); png_set_text(png_ptr, info_ptr, NULL, 0); // write the file information png_write_info(png_ptr, info_ptr); TRACEUSER( "Jonathan", _T("PNG write: pixel_depth %d channels %d\n"), png_get_bit_depth(png_ptr, info_ptr), png_get_channels(png_ptr, info_ptr)); TRACEUSER( "Jonathan", _T("PNG write: rowbytes %d color_type %d\n"), png_get_rowbytes(png_ptr, info_ptr), png_get_color_type(png_ptr, info_ptr)); // Set up the transformations you want. // Note: that these are all optional. Only call them if you want them // invert monocrome pixels //png_set_invert(png_ptr); // shift the pixels up to a legal bit depth and fill in as appropriate // to correctly scale the image //png_set_shift(png_ptr, &(info_ptr->sig_bit)); // pack pixels into bytes //png_set_packing(png_ptr); png_set_bgr(png_ptr); // swap bytes of 16 bit files to most significant bit first png_set_swap(png_ptr); // Must set the exception throwing and reporting flags back to their entry states File->SetThrowExceptions( OldThrowingState ); File->SetReportErrors( OldReportingState ); // er, we seem to have finished OK so say so return TRUE; } catch (...) { // catch our form of a file exception TRACE( _T("OutputPNG::OutputPNGHeader CC catch handler\n")); // Call up function to clean up the png structures CleanUpPngStructures(); // Must set the exception throwing and reporting flags back to their entry states File->SetThrowExceptions( OldThrowingState ); File->SetReportErrors( OldReportingState ); // We have finished so reset the PNG exception handling PNGUtil::SetCCFilePointer(NULL); return FALSE; } ERROR2( FALSE, "Escaped exception clause somehow" ); }
RADRT_API bool RADRT_CALL Encode(const Image &in, const Mipmap &mip, bool interlaced, void *&outData, AddrSize &outSize) { RAD_ASSERT(in.format == Format_A8 || in.format == Format_RGB888 || in.format == Format_RGBA8888); if (in.format != Format_A8 && in.format != Format_RGB888 && in.format != Format_RGBA8888) return false; png_structp png; png_infop info; png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, 0, PNGErrorHandler, PNGWarningHandler, 0, PNGMalloc, PNGFree); if (!png) return false; info = png_create_info_struct(png); if (!info) { png_destroy_write_struct(&png, 0); return false; } stream::DynamicMemOutputBuffer ob(ZImageCodec); stream::OutputStream os(ob); png_set_write_fn(png, &os, PNGWrite, PNGFlush); png_set_IHDR(png, info, mip.width, mip.height, 8, (in.format == Format_A8) ? PNG_COLOR_TYPE_GRAY : (in.format == Format_RGB888) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_color_8 sig; memset(&sig, 0, sizeof(sig)); if (in.format == Format_A8) { sig.gray = 8; } else { sig.red = 8; sig.green = 8; sig.blue = 8; sig.alpha = (in.format == Format_RGBA8888) ? 8 : 0; } png_set_sBIT(png, info, &sig); try { png_write_info(png, info); } catch (PNGException&) { png_destroy_write_struct(&png, &info); return false; } png_set_shift(png, &sig); int passes = 1; if (interlaced) { passes = png_set_interlace_handling(png); } for (int pass = 0; pass < passes; ++pass) { png_bytep src = (png_bytep)mip.data; for (int y = 0; y < mip.height; ++y) { png_write_rows(png, (png_bytepp)&src, 1); src += mip.stride; } } png_write_end(png, info); png_destroy_write_struct(&png, &info); outData = ob.OutputBuffer().Ptr(); outSize = ob.OutputBuffer().Size(); ob.OutputBuffer().Set(0, 0); // don't let the output buffer release the memory. return true; }
/* Test one file */ int test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) { static FILE *fpin, *fpout; /* "static" prevents setjmp corruption */ png_structp read_ptr, write_ptr; png_infop read_info_ptr, write_info_ptr, end_info_ptr, write_end_info_ptr; png_bytep row_buf; png_uint_32 y; png_uint_32 width, height; int num_pass, pass; int bit_depth, color_type; #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmp_env; #endif #endif char inbuf[256], outbuf[256]; row_buf = (png_bytep)NULL; if ((fpin = fopen(inname, "rb")) == NULL) { fprintf(STDERR, "Could not find input file %s\n", inname); return (1); } if ((fpout = fopen(outname, "wb")) == NULL) { fprintf(STDERR, "Could not open output file %s\n", outname); fclose(fpin); return (1); } png_debug(0, "Allocating read and write structures\n"); #ifdef PNG_USER_MEM_SUPPORTED read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL, (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); #else read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); #endif #if defined(PNG_NO_STDIO) png_set_error_fn(read_ptr, (png_voidp)inname, png_default_error, png_default_warning); #endif #ifdef PNG_USER_MEM_SUPPORTED write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL, (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); #else write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); #endif #if defined(PNG_NO_STDIO) png_set_error_fn(write_ptr, (png_voidp)inname, png_default_error, png_default_warning); #endif png_debug(0, "Allocating read_info, write_info and end_info structures\n"); read_info_ptr = png_create_info_struct(read_ptr); write_info_ptr = png_create_info_struct(write_ptr); end_info_ptr = png_create_info_struct(read_ptr); write_end_info_ptr = png_create_info_struct(write_ptr); #ifdef PNG_USER_MEM_SUPPORTED #endif #ifdef PNG_SETJMP_SUPPORTED png_debug(0, "Setting jmp_env for read struct\n"); #ifdef USE_FAR_KEYWORD if (setjmp(jmp_env)) #else if (setjmp(png_jmp_env(read_ptr))) #endif { fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr); fclose(fpin); fclose(fpout); return (1); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmp_env(read_ptr),jmp_env,sizeof(jmp_buf)); #endif png_debug(0, "Setting jmp_env for write struct\n"); #ifdef USE_FAR_KEYWORD if (setjmp(jmp_env)) #else if (setjmp(png_jmp_env(write_ptr))) #endif { fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr); fclose(fpin); fclose(fpout); return (1); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmp_env(write_ptr),jmp_env,sizeof(jmp_buf)); #endif #endif png_debug(0, "Initializing input and output streams\n"); #if !defined(PNG_NO_STDIO) png_init_io(read_ptr, fpin); png_init_io(write_ptr, fpout); #else png_set_read_fn(read_ptr, (png_voidp)fpin, png_default_read_data); png_set_write_fn(write_ptr, (png_voidp)fpout, png_default_write_data, #if defined(PNG_WRITE_FLUSH_SUPPORTED) png_default_flush); #else NULL); #endif #endif if(status_dots_requested == 1) { png_set_write_status_fn(write_ptr, write_row_callback); png_set_read_status_fn(read_ptr, read_row_callback); } else { png_set_write_status_fn(write_ptr, NULL); png_set_read_status_fn(read_ptr, NULL); } #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) { int i; for(i=0; i<256; i++) filters_used[i]=0; png_set_read_user_transform_fn(read_ptr, count_filters); } #endif #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) zero_samples=0; png_set_write_user_transform_fn(write_ptr, count_zero_samples); #endif #define HANDLE_CHUNK_IF_SAFE 2 #define HANDLE_CHUNK_ALWAYS 3 #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, NULL, 0); #endif #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, NULL, 0); #endif png_debug(0, "Reading info struct\n"); png_read_info(read_ptr, read_info_ptr); png_debug(0, "Transferring info struct\n"); { int interlace_type, compression_type, filter_type; if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type)) { png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, #if defined(PNG_WRITE_INTERLACING_SUPPORTED) color_type, interlace_type, compression_type, filter_type); #else color_type, PNG_INTERLACE_NONE, compression_type, filter_type); #endif } }
bool DeferredPNGWriter::begin( GFXFormat format, S32 width, S32 height, Stream &stream, U32 compressionLevel ) { // ONLY RGB bitmap writing supported at this time! AssertFatal( format == GFXFormatR8G8B8 || format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8 || format == GFXFormatA8 || format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time."); if ( format != GFXFormatR8G8B8 && format != GFXFormatR8G8B8A8 && format != GFXFormatR8G8B8X8 && format != GFXFormatA8 && format != GFXFormatR5G6B5 ) return false; mData->png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, pngFatalErrorFn, pngWarningFn, NULL, pngRealMallocFn, pngRealFreeFn); if (mData->png_ptr == NULL) return (false); mData->info_ptr = png_create_info_struct(mData->png_ptr); if (mData->info_ptr == NULL) { png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL); return false; } png_set_write_fn(mData->png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); // Set the compression level and image filters png_set_compression_window_bits(mData->png_ptr, 15); png_set_compression_level(mData->png_ptr, compressionLevel); png_set_filter(mData->png_ptr, 0, PNG_ALL_FILTERS); // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED if (format == GFXFormatR8G8B8) { png_set_IHDR(mData->png_ptr, mData->info_ptr, width, height, // the width & height 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8) { png_set_IHDR(mData->png_ptr, mData->info_ptr, width, height, // the width & height 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } else if (format == GFXFormatA8) { png_set_IHDR(mData->png_ptr, mData->info_ptr, width, height, // the width & height 8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } else if (format == GFXFormatR5G6B5) { png_set_IHDR(mData->png_ptr, mData->info_ptr, width, height, // the width & height 16, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, PNG_INTERLACE_NONE, // no interlace PNG_COMPRESSION_TYPE_DEFAULT, // compression type PNG_FILTER_TYPE_DEFAULT); // filter type png_color_8_struct sigBit = { 0 }; sigBit.gray = 16; png_set_sBIT(mData->png_ptr, mData->info_ptr, &sigBit ); png_set_swap( mData->png_ptr ); } png_write_info(mData->png_ptr, mData->info_ptr); mActive = true; return true; }
//-------------------------------------------------------------------------- static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter) { GFXFormat format = bitmap->getFormat(); // ONLY RGB bitmap writing supported at this time! AssertFatal( format == GFXFormatR8G8B8 || format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8 || format == GFXFormatA8 || format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time."); if ( format != GFXFormatR8G8B8 && format != GFXFormatR8G8B8A8 && format != GFXFormatR8G8B8X8 && format != GFXFormatA8 && format != GFXFormatR5G6B5 ) return false; png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, pngFatalErrorFn, pngWarningFn, NULL, pngMallocFn, pngFreeFn); if (png_ptr == NULL) return (false); png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return false; } png_set_write_fn(png_ptr, &stream, pngWriteDataFn, pngFlushDataFn); // Set the compression level and image filters png_set_compression_window_bits(png_ptr, 15); png_set_compression_level(png_ptr, compressionLevel); png_set_filter(png_ptr, 0, filter); // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED U32 width = bitmap->getWidth(); U32 height = bitmap->getHeight(); if (format == GFXFormatR8G8B8) { png_set_IHDR(png_ptr, info_ptr, width, height, // the width & height 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8) { png_set_IHDR(png_ptr, info_ptr, width, height, // the width & height 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } else if (format == GFXFormatA8) { png_set_IHDR(png_ptr, info_ptr, width, height, // the width & height 8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } else if (format == GFXFormatR5G6B5) { png_set_IHDR(png_ptr, info_ptr, width, height, // the width & height 16, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type, PNG_INTERLACE_NONE, // no interlace PNG_COMPRESSION_TYPE_DEFAULT, // compression type PNG_FILTER_TYPE_DEFAULT); // filter type png_color_8_struct sigBit = { 0 }; sigBit.gray = 16; png_set_sBIT(png_ptr, info_ptr, &sigBit ); png_set_swap( png_ptr ); } png_write_info(png_ptr, info_ptr); FrameAllocatorMarker marker; png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) ); for (U32 i=0; i<height; i++) row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i)); png_write_image(png_ptr, row_pointers); // Write S3TC data if present... // Write FXT1 data if present... png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return true; }
//============================================================== void PngWrite(char *file, int w, int h, u_char *ptr) //-------------------------------------------------------------- // データ出力 // 32bit → 32bit //-------------------------------------------------------------- // in: file = ファイル名 // w, h = データサイズ // ptr = データポインタ //-------------------------------------------------------------- // out: なし //============================================================== { sFILE *fp; png_structp png_ptr; png_infop info_ptr; png_color_8 sig_bit; png_text text_ptr[1]; png_bytep *row_pointers; int k; #ifdef USE_USER_MEMORY png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, libpng_Malloc, libpng_Free); #else png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif if(!png_ptr) { return; } info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_write_struct(&png_ptr, png_infopp_NULL); return; } // ファイルの新規作成 //-------------------- fp = FsCreate(file); ASSERT(fp); png_set_write_fn(png_ptr, (png_voidp)fp, writeFunc, flushFunc); png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE); sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; sig_bit.alpha = 0; png_set_sBIT(png_ptr, info_ptr, &sig_bit); text_ptr[0].key = "Description"; text_ptr[0].text = "ktcDIB::Save() Data"; text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; png_set_text(png_ptr, info_ptr, text_ptr, 1); png_write_info(png_ptr, info_ptr); png_set_bgr(png_ptr); row_pointers = (png_bytep *)fsMalloc(sizeof(png_bytep *) * h, "png_bytep"); ASSERT(row_pointers); for(k = 0; k < h; ++k) { png_byte *p; p = (png_byte *)fsMalloc(sizeof(png_byte) * w * 3, "png_byte"); ASSERT(p); row_pointers[k] = (png_bytep)p; memcpy(p, ptr, w * 3); ptr += w * 3; } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); for(k = 0; k < h; ++k) { Free(row_pointers[k]); } Free(row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); FsClose(fp); }
bool R9_ImgWritePNG( F9FILE file, r9Img* img ) { const int32 compressionlevel = 6; const int32 strategy = 0; const int32 filter = PNG_ALL_FILTERS; if(img->m_pf!=R9_PF_RGB && img->m_pf!=R9_PF_ARGB && img->m_pf!=R9_PF_BGR && img->m_pf!=R9_PF_ABGR ) { elog::rnd() << "png format not supported" << std::endl; return false; } png_structp png_ptr = png_create_write_struct_2( PNG_LIBPNG_VER_STRING, NULL, R9_ImgPNG_FatalError, R9_ImgPNG_Warning, NULL, R9_ImgPNG_Malloc, R9_ImgPNG_Free ); if(png_ptr==NULL) return false; png_infop info_ptr = png_create_info_struct(png_ptr); if(info_ptr==NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return false; } r9_imgpng_file = file; png_set_write_fn(png_ptr, NULL, R9_ImgPNG_WriteData, NULL); // last one was imgpng_flush (fflush) that did nothing // set the compression level, image filters, and compression strategy... png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; png_ptr->zlib_strategy = strategy; png_set_compression_window_bits(png_ptr, 15); png_set_compression_level(png_ptr, compressionlevel); png_set_filter(png_ptr, 0, filter); // flip rgb temporary, if necessarily - png likes BGR! if(img->m_pf==R9_PF_ARGB || img->m_pf==R9_PF_RGB) R9_ImgFlipRGB(img); // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED if(img->m_pf==R9_PF_RGB || img->m_pf==R9_PF_BGR) { png_set_IHDR(png_ptr, info_ptr, img->m_width, img->m_height, // the width & height 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } else if(img->m_pf==R9_PF_ARGB || img->m_pf==R9_PF_ABGR) { png_set_IHDR(png_ptr, info_ptr, img->m_width, img->m_height, // the width & height 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type, NULL, // no interlace NULL, // compression type NULL); // filter type } png_write_info(png_ptr, info_ptr); png_bytep* rowpointers = new png_bytep[img->m_height]; for(int i=0; i<img->m_height; i++) rowpointers[i] = (png_bytep)(img->m_data+(i*img->lineSize())); png_write_image(png_ptr, rowpointers); // release png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); delete [] rowpointers; r9_imgpng_file = NULL; // flip rgb back, if necessarily if(img->m_pf==R9_PF_ARGB || img->m_pf==R9_PF_RGB) R9_ImgFlipRGB(img); return true; }
//--------------------------------------------------------------------------- void __fastcall TDeePNG::SaveToStream(Classes::TStream * Stream) { // SaveToStream method // warning: this method would change the pixelformat to pf24bit // if the pixelformat is pfDevice, pf15bit, pf16bit, or pfCustom. png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep row_buffer = NULL; try { // create png_struct png_ptr = png_create_write_struct_2 (PNG_LIBPNG_VER_STRING, (png_voidp)this, DeePNG_error, DeePNG_warning, (png_voidp)this, DeePNG_malloc, DeePNG_free); // create png_info info_ptr = png_create_info_struct(png_ptr); // set write function png_set_write_fn(png_ptr, (png_voidp)Stream, DeePNG_write_data, DeePNG_flush); // set IHDR if(PixelFormat == pfDevice || PixelFormat == pf15bit || PixelFormat == pf16bit || PixelFormat == pfCustom) PixelFormat = pf24bit; bool grayscale = IsGrayscaleBitmap(this); int colordepth = GetBitmapColorDepth(this); int w = Width; int h = Height; int color_type; if(grayscale) color_type = PNG_COLOR_TYPE_GRAY; else if(colordepth <= 8) color_type = PNG_COLOR_TYPE_PALETTE; else if(colordepth == 32) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, w, h, colordepth < 8 ? colordepth : 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // set oFFs if(ofs_set) png_set_oFFs(png_ptr, info_ptr, ofs_x, ofs_y, ofs_unit); // set palette if(color_type == PNG_COLOR_TYPE_PALETTE) { png_color *palette = (png_colorp)png_malloc(png_ptr, 256 * sizeof(png_color)); PALETTEENTRY palentry[256]; int num_palette = GetPaletteEntries(Palette, 0, (1<<colordepth), palentry); for(int i = 0; i < num_palette; i++) { palette[i].red = palentry[i].peRed; palette[i].green = palentry[i].peGreen; palette[i].blue = palentry[i].peBlue; } png_set_PLTE(png_ptr, info_ptr, palette, num_palette); } // write info png_write_info(png_ptr, info_ptr); // write vpAg private chunk if(vpag_set) { png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; unsigned char vpag_chunk_data[9]; #define PNG_write_be32(p, a) (\ ((unsigned char *)(p))[0] = (unsigned char)(((a) >>24) & 0xff), \ ((unsigned char *)(p))[1] = (unsigned char)(((a) >>16) & 0xff), \ ((unsigned char *)(p))[2] = (unsigned char)(((a) >> 8) & 0xff), \ ((unsigned char *)(p))[3] = (unsigned char)(((a) ) & 0xff) ) PNG_write_be32(vpag_chunk_data, vpag_w); PNG_write_be32(vpag_chunk_data + 4, vpag_h); vpag_chunk_data[8] = (unsigned char)vpag_unit; png_write_chunk(png_ptr, png_vpAg, vpag_chunk_data, 9); } /* // change RGB order if(color_type = PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); // ???? why this does not work ? */ // write image if(color_type == PNG_COLOR_TYPE_RGB) { row_buffer = (png_bytep)png_malloc(png_ptr, 3 * w + 6); try { png_bytep row_pointer = row_buffer; for(int i = 0; i < h; i++) { png_bytep in = (png_bytep)ScanLine[i]; png_bytep out = row_buffer; for(int x = 0; x < w; x++) { out[2] = in[0]; out[1] = in[1]; out[0] = in[2]; out += 3; in += 3; } png_write_row(png_ptr, row_pointer); } } catch(...) { png_free(png_ptr, row_buffer); throw; } png_free(png_ptr, row_buffer); } else if(color_type == PNG_COLOR_TYPE_RGB_ALPHA) { row_buffer = (png_bytep)png_malloc(png_ptr, 4 * w + 6); try { png_bytep row_pointer = row_buffer; for(int i = 0; i < h; i++) { png_bytep in = (png_bytep)ScanLine[i]; png_bytep out = row_buffer; for(int x = 0; x < w; x++) { out[2] = in[0]; out[1] = in[1]; out[0] = in[2]; out[3] = in[3]; out += 4; in += 4; } png_write_row(png_ptr, row_pointer); } } catch(...) { png_free(png_ptr, row_buffer); throw; } png_free(png_ptr, row_buffer); } else { for(int i = 0; i < h; i++) { png_bytep row_pointer = (png_bytep)ScanLine[i]; png_write_row(png_ptr, row_pointer); } } // finish writing png_write_end(png_ptr, info_ptr); } catch(...) { png_destroy_write_struct(&png_ptr, &info_ptr); throw; } png_destroy_write_struct(&png_ptr, &info_ptr); }