void save_as_png(T1 & file, T2 const& image, png_options const& opts) { png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); if (!png_ptr) return; // switch on optimization only if supported #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED) png_uint_32 mask, flags; flags = png_get_asm_flags(png_ptr); mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(png_ptr, flags | mask); #endif png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,static_cast<png_infopp>(0)); return; } jmp_buf* jmp_context = static_cast<jmp_buf*>(png_get_error_ptr(png_ptr)); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn (png_ptr, &file, &write_data<T1>, &flush_data<T1>); png_set_compression_level(png_ptr, opts.compression); png_set_compression_strategy(png_ptr, opts.strategy); png_set_compression_buffer_size(png_ptr, 32768); png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8, (opts.trans_mode == 0) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); const std::unique_ptr<png_bytep[]> row_pointers(new png_bytep[image.height()]); for (unsigned int i = 0; i < image.height(); i++) { row_pointers[i] = const_cast<png_bytep>(reinterpret_cast<const unsigned char *>(image.get_row(i))); } png_set_rows(png_ptr, info_ptr, row_pointers.get()); png_write_png(png_ptr, info_ptr, (opts.trans_mode == 0) ? PNG_TRANSFORM_STRIP_FILLER_AFTER : PNG_TRANSFORM_IDENTITY, nullptr); png_destroy_write_struct(&png_ptr, &info_ptr); }
void save_as_png(T1 & file , T2 const& image, int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY) { png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); if (!png_ptr) return; // switch on optimization only if supported #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED) png_uint_32 mask, flags; flags = png_get_asm_flags(png_ptr); mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(png_ptr, flags | mask); #endif png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)0); return; } jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn (png_ptr, &file, &write_data<T1>, &flush_data<T1>); png_set_compression_level(png_ptr, compression); png_set_compression_strategy(png_ptr, strategy); png_set_compression_buffer_size(png_ptr, 32768); png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8, PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); for (unsigned i=0;i<image.height();i++) { png_write_row(png_ptr,(png_bytep)image.getRow(i)); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); }
void save_as_png(T & file, std::vector<mapnik::rgb> const& palette, mapnik::image_gray8 const& image, unsigned width, unsigned height, unsigned color_depth, std::vector<unsigned> const&alpha, png_options const& opts) { png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); if (!png_ptr) { return; } // switch on optimization only if supported #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED) png_uint_32 mask, flags; flags = png_get_asm_flags(png_ptr); mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(png_ptr, flags | mask); #endif png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,static_cast<png_infopp>(0)); return; } jmp_buf* jmp_context = static_cast<jmp_buf*>(png_get_error_ptr(png_ptr)); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn (png_ptr, &file, &write_data<T>, &flush_data<T>); png_set_compression_level(png_ptr, opts.compression); png_set_compression_strategy(png_ptr, opts.strategy); png_set_compression_buffer_size(png_ptr, 32768); png_set_IHDR(png_ptr, info_ptr,width,height,color_depth, PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); png_color* pal = const_cast<png_color*>(reinterpret_cast<const png_color*>(&palette[0])); png_set_PLTE(png_ptr, info_ptr, pal, static_cast<unsigned>(palette.size())); // make transparent lowest indexes, so tRNS is small if (alpha.size()>0) { std::vector<png_byte> trans(alpha.size()); unsigned alphaSize=0;//truncate to nonopaque values for(unsigned i=0; i < alpha.size(); i++) { trans[i]=alpha[i]; if (alpha[i]<255) { alphaSize = i+1; } } if (alphaSize>0) { png_set_tRNS(png_ptr, info_ptr, static_cast<png_bytep>(&trans[0]), alphaSize, 0); } } png_write_info(png_ptr, info_ptr); for (unsigned i=0;i<height;i++) { png_write_row(png_ptr,const_cast<png_bytep>(image.get_row(i))); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); }
void save_as_png(T1 & file, T2 const& image, int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY, int alpha = false, bool use_miniz = false) { if (use_miniz) { MiniZ::PNGWriter writer(compression); if (alpha) { writer.writeIHDR(image.width(), image.height(), 32); writer.writeIDAT(image); } else { writer.writeIHDR(image.width(), image.height(), 24); writer.writeIDATStripAlpha(image); } writer.writeIEND(); writer.toStream(file); return; } png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); if (!png_ptr) return; // switch on optimization only if supported #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED) png_uint_32 mask, flags; flags = png_get_asm_flags(png_ptr); mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(png_ptr, flags | mask); #endif png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)0); return; } jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn (png_ptr, &file, &write_data<T1>, &flush_data<T1>); png_set_compression_level(png_ptr, compression); png_set_compression_strategy(png_ptr, strategy); png_set_compression_buffer_size(png_ptr, 32768); png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), 8, alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_bytep row_pointers[image.height()]; for (unsigned int i = 0; i < image.height(); i++) { row_pointers[i] = (png_bytep)image.getRow(i); } png_set_rows(png_ptr, info_ptr, (png_bytepp)&row_pointers); png_write_png(png_ptr, info_ptr, alpha ? PNG_TRANSFORM_IDENTITY : PNG_TRANSFORM_STRIP_FILLER_AFTER, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); }
void save_as_png(T & file, std::vector<rgb> const& palette, image_data_8 const& image, unsigned width, unsigned height, unsigned color_depth, int compression, int strategy, std::vector<unsigned> const&alpha, bool use_miniz) { if (use_miniz) { MiniZ::PNGWriter writer(compression); // image.width()/height() does not reflect the actual image dimensions; it // refers to the quantized scanlines. writer.writeIHDR(width, height, color_depth); writer.writePLTE(palette); writer.writetRNS(alpha); writer.writeIDAT(image); writer.writeIEND(); writer.toStream(file); return; } png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); if (!png_ptr) return; // switch on optimization only if supported #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED) png_uint_32 mask, flags; flags = png_get_asm_flags(png_ptr); mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(png_ptr, flags | mask); #endif png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)0); return; } jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn (png_ptr, &file, &write_data<T>, &flush_data<T>); png_set_compression_level(png_ptr, compression); png_set_compression_strategy(png_ptr, strategy); png_set_compression_buffer_size(png_ptr, 32768); png_set_IHDR(png_ptr, info_ptr,width,height,color_depth, PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); png_color* pal = const_cast<png_color*>(reinterpret_cast<const png_color*>(&palette[0])); png_set_PLTE(png_ptr, info_ptr, pal, palette.size()); // make transparent lowest indexes, so tRNS is small if (alpha.size()>0) { std::vector<png_byte> trans(alpha.size()); unsigned alphaSize=0;//truncate to nonopaque values for(unsigned i=0; i < alpha.size(); i++) { trans[i]=alpha[i]; if (alpha[i]<255) alphaSize = i+1; } if (alphaSize>0) png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0); } png_write_info(png_ptr, info_ptr); for (unsigned i=0; i<height; i++) { png_write_row(png_ptr,(png_bytep)image.getRow(i)); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); }
// ###################################################################### PngParser::PngParser(const char* filename) : rep(new Rep(filename)) { errno = 0; rep->file = fopen(filename, "rb"); if (rep->file == 0) rep->onError("couldn't open file for png reading"); const size_t nheader = 8; png_byte header[nheader]; if (fread(header, 1, nheader, rep->file) != nheader) rep->onError("short read on png file header"); int is_png = !png_sig_cmp(header, 0, nheader); if (!is_png) rep->onError("file was not a png image file"); rep->pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (rep->pngPtr == 0) rep->onError("png_create_read_struct failed"); rep->infoPtr = png_create_info_struct(rep->pngPtr); if (rep->infoPtr == 0) rep->onError("png_create_info_struct failed"); rep->endPtr = png_create_info_struct(rep->pngPtr); if (rep->endPtr == 0) rep->onError("png_create_info_struct failed"); png_init_io(rep->pngPtr, rep->file); png_set_sig_bytes(rep->pngPtr, nheader); png_read_info(rep->pngPtr, rep->infoPtr); rep->bitDepth = png_get_bit_depth(rep->pngPtr, rep->infoPtr); rep->colorType = png_get_color_type(rep->pngPtr, rep->infoPtr); if (rep->bitDepth == 16) png_set_strip_16(rep->pngPtr); else if (rep->bitDepth < 8 && (rep->colorType == PNG_COLOR_TYPE_GRAY)) png_set_gray_1_2_4_to_8(rep->pngPtr); else if (rep->bitDepth != 8 && (rep->colorType != PNG_COLOR_TYPE_PALETTE)) rep->onError(sformat("invalid bit-depth(%d)/color-mode(%d) " "combination", rep->bitDepth, rep->colorType)); // Strip out the alpha channel, if present if (rep->colorType & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(rep->pngPtr); if (rep->colorType & PNG_COLOR_MASK_PALETTE) png_set_palette_to_rgb(rep->pngPtr); // This must come after any+all transformations are specified png_read_update_info(rep->pngPtr, rep->infoPtr); // These calls must come after png_read_update_info, so that we get // values that reflect any transformations rep->width = png_get_image_width(rep->pngPtr, rep->infoPtr); rep->height = png_get_image_height(rep->pngPtr, rep->infoPtr); rep->rowBytes = png_get_rowbytes(rep->pngPtr, rep->infoPtr); rep->numChannels = png_get_channels(rep->pngPtr, rep->infoPtr); ASSERT(rep->rowBytes = rep->width*rep->numChannels); // run-time mmx PNG optimizations (nate) #if defined(HAVE_PNG_ASM_FLAGS) const png_uint_32 flags = png_get_asm_flags(rep->pngPtr); const png_uint_32 mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(rep->pngPtr, flags | mask); #endif }
int readpng2_init(mainprog_info *mainprog_ptr) { png_structp png_ptr; /* note: temporary variables! */ png_infop info_ptr; /* could also replace libpng warning-handler (final NULL), but no need: */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, readpng2_error_handler, NULL); if (!png_ptr) return 4; /* out of memory */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return 4; /* out of memory */ } /* we could create a second info struct here (end_info), but it's only * useful if we want to keep pre- and post-IDAT chunk info separated * (mainly for PNG-aware image editors and converters) */ /* setjmp() must be called in every function that calls a PNG-reading * libpng function, unless an alternate error handler was installed-- * but compatible error handlers must either use longjmp() themselves * (as in this program) or exit immediately, so here we are: */ if (setjmp(mainprog_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 2; } #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED /* prepare the reader to ignore all recognized chunks whose data won't be * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT, * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */ { /* These byte strings were copied from png.h. If a future libpng * version recognizes more chunks, add them to this list. If a * future version of readpng2.c recognizes more chunks, delete them * from this list. */ static const png_byte chunks_to_ignore[] = { 99, 72, 82, 77, '\0', /* cHRM */ 104, 73, 83, 84, '\0', /* hIST */ 105, 67, 67, 80, '\0', /* iCCP */ 105, 84, 88, 116, '\0', /* iTXt */ 111, 70, 70, 115, '\0', /* oFFs */ 112, 67, 65, 76, '\0', /* pCAL */ 112, 72, 89, 115, '\0', /* pHYs */ 115, 66, 73, 84, '\0', /* sBIT */ 115, 67, 65, 76, '\0', /* sCAL */ 115, 80, 76, 84, '\0', /* sPLT */ 115, 84, 69, 82, '\0', /* sTER */ 116, 69, 88, 116, '\0', /* tEXt */ 116, 73, 77, 69, '\0', /* tIME */ 122, 84, 88, 116, '\0' /* zTXt */ }; png_set_keep_unknown_chunks(png_ptr, 1 /* PNG_HANDLE_CHUNK_NEVER */, chunks_to_ignore, sizeof(chunks_to_ignore)/5); } #endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */ /* instead of doing png_init_io() here, now we set up our callback * functions for progressive decoding */ png_set_progressive_read_fn(png_ptr, mainprog_ptr, readpng2_info_callback, readpng2_row_callback, readpng2_end_callback); /* * may as well enable or disable MMX routines here, if supported; * * to enable all: mask = png_get_mmx_flagmask ( * PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID); * flags = png_get_asm_flags (png_ptr); * flags |= mask; * png_set_asm_flags (png_ptr, flags); * * to disable all: mask = png_get_mmx_flagmask ( * PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID); * flags = png_get_asm_flags (png_ptr); * flags &= ~mask; * png_set_asm_flags (png_ptr, flags); */ #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \ defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) /* * WARNING: This preprocessor approach means that the following code * cannot be used with a libpng DLL older than 1.2.0--the * compiled-in symbols for the new functions will not exist. * (Could use dlopen() and dlsym() on Unix and corresponding * calls for Windows, but not portable...) */ { #ifdef PNG_ASSEMBLER_CODE_SUPPORTED png_uint_32 mmx_disable_mask = 0; png_uint_32 asm_flags, mmx_mask; int compilerID; if (mainprog_ptr->nommxfilters) mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); if (mainprog_ptr->nommxcombine) mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_COMBINE_ROW; if (mainprog_ptr->nommxinterlace) mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_INTERLACE; asm_flags = png_get_asm_flags(png_ptr); png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask); /* Now query libpng's asm settings, just for yuks. Note that this * differs from the querying of its *potential* MMX capabilities * in readpng2_version_info(); this is true runtime verification. */ asm_flags = png_get_asm_flags(png_ptr); mmx_mask = png_get_mmx_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID); if (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_COMPILED) fprintf(stderr, " MMX support (%s version) is compiled into libpng\n", compilerID == 1? "MSVC++" : (compilerID == 2? "GNU C" : "unknown")); else fprintf(stderr, " MMX support is not compiled into libpng\n"); fprintf(stderr, " MMX instructions are %ssupported by CPU\n", (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU)? "" : "not "); fprintf(stderr, " MMX read support for combining rows is %sabled\n", (asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)? "en" : "dis"); fprintf(stderr, " MMX read support for expanding interlacing is %sabled\n", (asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)? "en" : "dis"); fprintf(stderr, " MMX read support for \"sub\" filter is %sabled\n", (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "en" : "dis"); fprintf(stderr, " MMX read support for \"up\" filter is %sabled\n", (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "en" : "dis"); fprintf(stderr, " MMX read support for \"avg\" filter is %sabled\n", (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "en" : "dis"); fprintf(stderr, " MMX read support for \"Paeth\" filter is %sabled\n", (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "en" : "dis"); asm_flags &= (mmx_mask & ~( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ | PNG_ASM_FLAG_MMX_READ_INTERLACE \ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH )); if (asm_flags) fprintf(stderr, " additional MMX support is also enabled (0x%02lx)\n", asm_flags); #else /* !PNG_ASSEMBLER_CODE_SUPPORTED */ fprintf(stderr, " MMX querying is disabled in libpng.\n"); #endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ } #endif /* make sure we save our pointers for use in readpng2_decode_data() */ mainprog_ptr->png_ptr = png_ptr; mainprog_ptr->info_ptr = info_ptr; /* and that's all there is to initialization */ return 0; }
void save_as_png(T & file, std::vector<mapnik::rgb> & palette, mapnik::image_data_8 const& image, unsigned width, unsigned height, unsigned color_depth, std::vector<unsigned> &alpha) { png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); if (!png_ptr) return; // switch on optimization only if supported #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED) png_uint_32 mask, flags; flags = png_get_asm_flags(png_ptr); mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); png_set_asm_flags(png_ptr, flags | mask); #endif png_set_filter (png_ptr, 0, PNG_FILTER_NONE); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)0); return; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn (png_ptr, &file, &write_data<T>, &flush_data<T>); png_set_IHDR(png_ptr, info_ptr,width,height,color_depth, PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); png_set_PLTE(png_ptr,info_ptr,reinterpret_cast<png_color*>(&palette[0]),palette.size()); // make transparent lowest indexes, so tRNS is small if (alpha.size()>0) { std::vector<png_byte> trans(alpha.size()); unsigned alphaSize=0;//truncate to nonopaque values for(unsigned i=0; i < alpha.size(); i++) { trans[i]=alpha[i]; if (alpha[i]<255) alphaSize = i+1; } if (alphaSize>0) png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0); } png_write_info(png_ptr, info_ptr); for (unsigned i=0;i<height;i++) { png_write_row(png_ptr,(png_bytep)image.getRow(i)); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); }