void save_to_png(char* filename) { int i; // use malloc rather than the stack since an array of several million bytes will overflow the stack uint8_t *pixels = malloc(width * height * 3 * sizeof(uint8_t)); // switch the framebuffer in order to force the full texture to be saved glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[fb]); glViewport(0, 0, width, height); // copy pixels from screen glActiveTexture(0); glBindTexture(GL_TEXTURE_2D, textures[fb]); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)pixels); // use libpng to write the pixels to a png image png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) goto png_fail; png_infop info = png_create_info_struct(png); if (!info) { png_destroy_write_struct(&png, &info); goto png_fail; } if(filename == NULL) { // filename => current time in milliseconds char tmp[256]; snprintf(tmp, 256, "%llu.png", get_time_us() * 1000); filename = tmp; } FILE *file = fopen(filename, "wb"); if (!file) { png_destroy_write_struct(&png, &info); goto png_fail; } png_init_io(png, file); png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_colorp palette = png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); if (!palette) { fclose(file); png_destroy_write_struct(&png, &info); goto png_fail; } png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png, info); png_set_packing(png); png_bytepp rows = (png_bytepp)png_malloc(png, height * sizeof(png_bytep)); for (i = 0; i < height; ++i) { rows[i] = (png_bytep)(pixels + (height - i - 1) * width * 3); } png_write_image(png, rows); png_write_end(png, info); png_free(png, palette); png_destroy_write_struct(&png, &info); fclose(file); free(pixels); printf("PNG: finished at %llu\n", get_time_us()); render_prepare_screen(); return; png_fail: fail("Failed to create PNG\n"); }
static int write_png_palette( png_struct *png_ptr, png_info *info_ptr, SDL_Surface *scr) { int i, result = -1; png_color *palette; palette = malloc(sizeof(*palette) * scr->format->palette->ncolors); if (palette) { // Convert SDL palette to libpng for (i = 0; i < scr->format->palette->ncolors; i++) { palette[i].red = scr->format->palette->colors[i].r; palette[i].green = scr->format->palette->colors[i].g; palette[i].blue = scr->format->palette->colors[i].b; } png_set_PLTE(png_ptr, info_ptr, palette, scr->format->palette->ncolors); free(palette); result = 0; } return result; }
pngquant_error rwpng_write_image8(FILE *outfile, png8_image *mainprog_ptr) { png_structp png_ptr; png_infop info_ptr; pngquant_error retval = rwpng_write_image_init((png_image*)mainprog_ptr, &png_ptr, &info_ptr, outfile); if (retval) return retval; /* set the image parameters appropriately */ int sample_depth; if (mainprog_ptr->num_palette <= 2) sample_depth = 1; else if (mainprog_ptr->num_palette <= 4) sample_depth = 2; else if (mainprog_ptr->num_palette <= 16) sample_depth = 4; else sample_depth = 8; png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height, sample_depth, PNG_COLOR_TYPE_PALETTE, 0, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE); png_set_PLTE(png_ptr, info_ptr, &mainprog_ptr->palette[0], mainprog_ptr->num_palette); if (mainprog_ptr->num_trans > 0) png_set_tRNS(png_ptr, info_ptr, mainprog_ptr->trans, mainprog_ptr->num_trans, NULL); rwpng_write_end(&info_ptr, &png_ptr, (png_image*)mainprog_ptr); return SUCCESS; }
static int save_png_sub(RefImage *image, Value w) { png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info_ptr = png_create_info_struct(png_ptr); png_bytepp rows = malloc(sizeof(png_bytep) * image->height); png_bytep data = (png_bytep)image->data; int color_type = PNG_COLOR_TYPE_RGB; int i; png_set_write_fn(png_ptr, &w, png_write_callback, png_flush_callback); switch (image->bands) { case BAND_L: color_type = PNG_COLOR_TYPE_GRAY; break; case BAND_LA: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case BAND_P: color_type = PNG_COLOR_TYPE_PALETTE; break; case BAND_RGB: color_type = PNG_COLOR_TYPE_RGB; break; case BAND_RGBA: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); free(rows); return FALSE; } png_set_IHDR(png_ptr, info_ptr, image->width, image->height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); for (i = 0; i < image->height; i++) { rows[i] = data + image->pitch * i; } if (image->bands == BAND_P) { uint32_t *pal = image->palette; uint8_t trans[PALETTE_NUM]; png_color pcolor[PALETTE_NUM]; if (palette_has_alpha(pal)) { for (i = 0; i < PALETTE_NUM; i++) { trans[i] = (pal[i] & COLOR_A_MASK) >> COLOR_A_SHIFT; } png_set_tRNS(png_ptr, info_ptr, trans, PALETTE_NUM, NULL); } for (i = 0; i < PALETTE_NUM; i++) { pcolor[i].red = (pal[i] & COLOR_R_MASK) >> COLOR_R_SHIFT; pcolor[i].green = (pal[i] & COLOR_G_MASK) >> COLOR_G_SHIFT; pcolor[i].blue = (pal[i] & COLOR_B_MASK) >> COLOR_B_SHIFT; } png_set_PLTE(png_ptr, info_ptr, pcolor, PALETTE_NUM); }
void writeSetup2(png_structp png_ptr_write, png_infop info_ptr_write, png_structp png_ptr_read, png_infop info_ptr_read) { /* IHDR */ png_uint_32 width; png_uint_32 height; int bit_depth; int colour_type; int interlace_method; int compression_method; int filter_method; /* PLTE */ png_colorp palette = NULL; int palette_size = 0; /* gAMA */ double gamma; /* tRNS */ png_bytep trans; int num_trans; png_color_16p trans_values; /* bKGD */ png_color_16p background; png_get_IHDR(png_ptr_read, info_ptr_read, &width, &height, &bit_depth, &colour_type, &interlace_method, &compression_method, &filter_method); png_set_IHDR(png_ptr_write, info_ptr_write, width, height, bit_depth, colour_type, interlace_method, compression_method, filter_method); if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_PLTE)) { png_get_PLTE(png_ptr_read, info_ptr_read, &palette, &palette_size); png_set_PLTE(png_ptr_write, info_ptr_write, palette, palette_size); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_gAMA)) { png_get_gAMA(png_ptr_read, info_ptr_read, &gamma); png_set_gAMA(png_ptr_write, info_ptr_write, gamma); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_tRNS)) { png_get_tRNS(png_ptr_read, info_ptr_read, &trans, &num_trans, &trans_values); png_set_tRNS(png_ptr_write, info_ptr_write, trans, num_trans, trans_values); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_bKGD)) { png_get_bKGD(png_ptr_read, info_ptr_read, &background); png_set_bKGD(png_ptr_write, info_ptr_write, background); } }
/** Write out the PLTE (and possibly tRNS) chunk to the png. This will create the * palette data to set in the PLTE chunk and set it, and if the colorkey is set * for the surface an appropriate tRNS chunk is generated. * * \param png_ptr A pointer to the png write structure. * \param info_ptr A pointer to the png info structure. * \param surf The surface that is being written to the png. * \return -1 on error, 0 if the palette chunk was written without problems. */ static int write_palette_chunk(png_structp png_ptr, png_infop info_ptr, SDL_Surface *surf) { png_colorp palette; Uint8 *alphas; int slot; SDL_PixelFormat *fmt = surf -> format; SDL_Color *sourcepal = fmt -> palette -> colors; // Write the image header first... png_set_IHDR(png_ptr, info_ptr, surf -> w, surf -> h, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // now sort out the palette if(!(palette = (png_colorp)malloc(fmt -> palette -> ncolors * sizeof(png_color)))) { SDL_SetError("Unable to create memory for palette storage"); return -1; } // Copy the palette over. Can't just use a straight // memcpy as sdl palettes have pad bytes. for(slot = 0; slot < fmt -> palette -> ncolors; ++slot) { memcpy(&palette[slot], &sourcepal[slot], 3); } // Set it... png_set_PLTE(png_ptr, info_ptr, palette, fmt -> palette -> ncolors); // Done with the palette now free(palette); Uint32 colorkey; int ck = SDL_GetColorKey(surf, &colorkey); // If we have a colour key, we need to set up the alphas for each palette colour if(ck == 0) { // According the the PNG spec (section 4.2.1.1) we only need enough entries // to store transparencies up to the transparent pixel. if(!(alphas = (Uint8 *)malloc((colorkey + 1) * sizeof(Uint8)))) { SDL_SetError("Unable to create memory for transparency storage"); return -1; } // Set all of the alpha values to full memset(alphas, 255, (colorkey + 1) * sizeof(Uint8)); // And handle the transparent pixel alphas[colorkey] = 0; // Write the chunk, and then we're done with the transparencies png_set_tRNS(png_ptr, info_ptr, alphas, colorkey + 1, NULL); free(alphas); } return 0; }
/* * Saves a byte array stored in pixels of width w and height h as a png into * filename */ GLuint save_png (const char * filename, GLubyte * pixels, GLuint w, GLuint h) { png_structp png; png_infop info; png_colorp palette; png_bytepp rows; FILE * fp; GLuint i; png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) return 1; info = png_create_info_struct(png); if(!info) { png_destroy_write_struct(&png, NULL); return 1; } fp = fopen(filename, "wb"); if (!fp) { png_destroy_write_struct(&png, &info); return 1; } png_init_io(png, fp); png_set_IHDR(png, info, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); palette = (png_colorp) png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); if (!palette) { fclose(fp); png_destroy_write_struct(&png, &info); return 1; } png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png, info); png_set_packing(png); rows = (png_bytepp) png_malloc(png, h * sizeof(png_bytep)); for (i = 0; i < h; ++i) rows[i] = (png_bytep) (pixels + (h - i - 1) * w * 3); png_write_image(png, rows); png_write_end(png, info); png_free(png, palette); png_destroy_write_struct(&png, &info); fclose(fp); free(rows); return 0; }
void gdImagePng(gdImagePtr im, FILE *out) { int i; png_colorp palette; png_structp png_write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, /* we would need to point to error handlers here to do it properly */ (png_error_ptr)NULL, (png_error_ptr)NULL); png_infop info_ptr = png_create_info_struct(png_write_ptr); if (setjmp(gdPngJmpbufStruct.jmpbuf)) { png_destroy_write_struct(&png_write_ptr, &info_ptr); return; } palette = (png_colorp)png_malloc (png_write_ptr, im->colorsTotal*sizeof(png_color)); if (palette == NULL) { png_destroy_write_struct(&png_write_ptr, &info_ptr); return; } png_init_io(png_write_ptr, out); png_set_write_status_fn(png_write_ptr, NULL); png_set_IHDR(png_write_ptr,info_ptr, im->sx,im->sy,im->colorsTotal > 16 ? 8:4, PNG_COLOR_TYPE_PALETTE, im->interlace ? PNG_INTERLACE_ADAM7: PNG_INTERLACE_NONE , PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); for(i=0; i<im->colorsTotal; i++) { palette[i].red = im->red[i]; palette[i].green = im->green[i]; palette[i].blue = im->blue[i]; } png_set_PLTE(png_write_ptr, info_ptr, palette, im->colorsTotal); /* choose between speed (1) and space (9) optimization */ /* we want to be fast ... */ png_set_compression_level(png_write_ptr,1); png_set_filter(png_write_ptr,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS); /* store file info */ png_write_info(png_write_ptr, info_ptr); png_set_packing(png_write_ptr); png_write_image(png_write_ptr, im->pixels); png_write_end(png_write_ptr, info_ptr); png_free(png_write_ptr, palette); png_destroy_write_struct(&png_write_ptr, &info_ptr); }
/* * Change the size of the palette buffer. * Changing info_ptr->num_palette directly, avoiding reallocation, should * have been sufficient, but can't be done using the current libpng API. */ static void opng_realloc_PLTE(png_structp png_ptr, png_infop info_ptr, int num_palette) { png_colorp palette; int src_num_palette = 0; png_get_PLTE(png_ptr, info_ptr, &palette, &src_num_palette); if (num_palette == src_num_palette) {return;} png_color buffer[PNG_MAX_PALETTE_LENGTH]; memcpy(buffer, palette, num_palette * sizeof(png_color)); if (num_palette > src_num_palette) memset(buffer + src_num_palette, 0, (num_palette - src_num_palette) * sizeof(png_color)); png_set_PLTE(png_ptr, info_ptr, buffer, num_palette); }
extern void bitmap_write(struct bitmap *bitmap) { if (!output_path && is_tty_stdout()) message_fatal("Data cannot be written to a terminal"); FILE *fp = output_path ? fopen(output_path, "wb") : stdout; if (fp == NULL) message_fatal("Unable to open file for writing"); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) message_fatal("Unable to create png struct"); png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) message_fatal("Unable to create png info struct"); if (setjmp(png_jmpbuf(png_ptr))) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); message_fatal("Error writing png file"); } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, bitmap->width, bitmap->height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_color *palette = palette_create(); png_set_PLTE(png_ptr, info_ptr, palette, 256); png_bytep row_pointers[bitmap->height]; for (unsigned y = 0; y < bitmap->height; y++) row_pointers[y] = bitmap->data + bitmap->width * y; png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); palette_release(palette); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); }
static void pngx_set_GIF_palette(png_structp png_ptr, png_infop info_ptr, unsigned char *color_table, unsigned int num_colors) { png_color palette[256]; unsigned int i; PNGX_ASSERT(color_table != NULL && num_colors <= 256); for (i = 0; i < num_colors; ++i) { palette[i].red = color_table[3 * i]; palette[i].green = color_table[3 * i + 1]; palette[i].blue = color_table[3 * i + 2]; } png_set_PLTE(png_ptr, info_ptr, palette, (int)num_colors); }
/* * bta_transparent_toPNG */ void bta_transparent_toPNG(bta_cell_t *in, btstring_t *fname) { FILE *outfp; png_structp png_ptr; png_infop info_ptr; uint32_t i; int trans = 0; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("Failed allocating png_ptr\n"); return; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { printf("Failed allocating info_ptr\n"); return; } outfp = fopen(fname->buf, "wb"); if (outfp == NULL) { printf("Error opening %s\n", fname->buf); return; } png_init_io(png_ptr, outfp); png_set_IHDR(png_ptr, info_ptr, in->width, in->height, 8, \ PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, \ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_PLTE(png_ptr, info_ptr, egapalette, 16); png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans, 1, NULL); png_write_info(png_ptr, info_ptr); for (i = 0; i < in->height; i++) png_write_row(png_ptr, &in->gfx->buf[i * in->width]); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(outfp); bts_free(fname); }
void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette) { png_colorp colors = malloc(palette->numColors * sizeof(png_color)); if (colors == NULL) FATAL_ERROR("Failed to allocate PNG palette.\n"); for (int i = 0; i < palette->numColors; i++) { colors[i].red = palette->colors[i].red; colors[i].green = palette->colors[i].green; colors[i].blue = palette->colors[i].blue; } png_set_PLTE(png_ptr, info_ptr, colors, palette->numColors); free(colors); }
void Texture::SaveTexture( const OutPutTextureData& saveto ) { unsigned long i; png_structp png_ptr; png_infop info_ptr; png_colorp palette; png_byte *image; png_bytep *row_pointers; IFile* writefile = IOSystem::Instance().FileFactory(saveto.m_Path); writefile->OpenFile( IFile::AT_READ ); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); png_set_write_fn( png_ptr, writefile, png_rw, png_flush ); //png_init_io(png_ptr, writefile.BaseFile() ); int colortype, bitesize; switch( saveto.m_Pixel ) { case Device::PF_R8G8B8: colortype = PNG_COLOR_TYPE_RGB; bitesize = 3; break; case Device::PF_R8G8B8A8: colortype = PNG_COLOR_TYPE_RGBA; bitesize = 4; break; } png_set_IHDR(png_ptr, info_ptr, saveto.m_Size.m_x, saveto.m_Size.m_y, 8, colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); row_pointers = (png_bytep *)malloc(saveto.m_Size.m_y * sizeof(png_bytep)); for (i = 0; i < saveto.m_Size.m_y; i++) { row_pointers[i] = (png_bytep)&saveto.m_Data[i * saveto.m_Size.m_y * bitesize]; } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); png_free(png_ptr, palette); palette = NULL; png_destroy_write_struct(&png_ptr, &info_ptr); free(row_pointers); row_pointers = NULL; writefile->CloseFile( ); IOSystem::Instance().FileDestroy( writefile ); }
int savePNG(const char * fileName,uint32_t width,uint32_t height,void * ptr,uint8_t*pal,unsigned pn){ //saves a 24bit png with rgb byte order png_byte * dat=(png_byte*)ptr;//convert to uint8_t FILE * fp=fopen(fileName,"wb"); if (!fp) return 1; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)0,0,0); if (!png_ptr){ fclose(fp); return 1; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr){ png_destroy_write_struct(&png_ptr,(png_infopp)NULL); return 1; } if (setjmp(png_jmpbuf(png_ptr))){ png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return 1; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, width, height,8,pal?PNG_COLOR_TYPE_PALETTE:PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);//must be called before other png_set_*() functions png_color_struct*palTmp=0; if(pal){ palTmp=(png_color_struct*)malloc(pn*sizeof(png_color_struct)); for(unsigned i=0;i<pn;++i){ palTmp[i].red=pal[i*3]; palTmp[i].green=pal[i*3+1]; palTmp[i].blue=pal[i*3+2]; } png_set_PLTE(png_ptr,info_ptr,palTmp,pn); } png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); uint32_t y; png_set_user_limits(png_ptr, width, height); png_write_info(png_ptr, info_ptr); for (y=0;y<height;++y) png_write_row(png_ptr, &dat[(y*width*(pal?1:3))]); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp);//done with file free(palTmp); return 0;//will return 0 on success non-zero in error }
void write() const { assert(m_png); assert(m_info); sync_ihdr(); if (m_color_type == color_type_palette) { if (! m_palette.empty()) { png_set_PLTE(m_png, m_info, const_cast< color* >(& m_palette[0]), (int) m_palette.size()); } if (! m_tRNS.empty()) { #ifdef PNG_tRNS_SUPPORTED png_set_tRNS(m_png, m_info, const_cast< byte* >(& m_tRNS[0]), m_tRNS.size(), NULL); #else throw error("attempted to write tRNS chunk; recompile with PNG_tRNS_SUPPORTED"); #endif } } if (m_gamma > 0) { #ifdef PNG_gAMA_SUPPORTED #ifdef PNG_FLOATING_POINT_SUPPORTED png_set_gAMA(m_png, m_info, m_gamma); #else png_set_gAMA_fixed(m_png, m_info, (png_fixed_point)(m_gamma * 100000)); #endif #else throw error("attempted to write gAMA chunk; recompile with PNG_gAMA_SUPPORTED"); #endif } png_write_info(m_png, m_info); }
pngquant_error rwpng_write_image8(FILE *outfile, png8_image *mainprog_ptr) { png_structp png_ptr; png_infop info_ptr; pngquant_error retval = rwpng_write_image_init((png_image*)mainprog_ptr, &png_ptr, &info_ptr, outfile); if (retval) return retval; // Palette images generally don't gain anything from filtering png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_VALUE_NONE); rwpng_set_gamma(info_ptr, png_ptr, mainprog_ptr->gamma); /* set the image parameters appropriately */ int sample_depth; if (mainprog_ptr->num_palette <= 2) sample_depth = 1; else if (mainprog_ptr->num_palette <= 4) sample_depth = 2; else if (mainprog_ptr->num_palette <= 16) sample_depth = 4; else sample_depth = 8; png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height, sample_depth, PNG_COLOR_TYPE_PALETTE, 0, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE); png_set_PLTE(png_ptr, info_ptr, &mainprog_ptr->palette[0], mainprog_ptr->num_palette); if (mainprog_ptr->num_trans > 0) png_set_tRNS(png_ptr, info_ptr, mainprog_ptr->trans, mainprog_ptr->num_trans, NULL); png_bytepp row_pointers = rwpng_create_row_pointers(info_ptr, png_ptr, mainprog_ptr->indexed_data, mainprog_ptr->height, mainprog_ptr->width); rwpng_write_end(&info_ptr, &png_ptr, row_pointers); free(row_pointers); return SUCCESS; }
UT_Error IE_ImpGraphic_Win32Native::Convert_BMP_Palette(UT_ByteBuf* pBB) { /* Reset error handling for libpng */ if (setjmp(m_pPNG->jmpbuf)) { png_destroy_write_struct(&m_pPNG, &m_pPNGInfo); return UT_ERROR; } png_set_IHDR ( m_pPNG, m_pPNGInfo, m_iWidth, m_iHeight, m_iBitsPerPlane, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); UT_uint32 iOffset = m_iHeaderSize + 14; UT_uint32 numClrs = (m_iClrUsed > 0) ? m_iClrUsed : (m_iOffset - iOffset)/((m_bOldBMPFormat)?3:4); png_colorp palette = static_cast<png_colorp>(png_malloc(m_pPNG, numClrs * sizeof(png_color))); for (UT_uint32 i=0; i < numClrs; i++) { palette[i].blue = ReadByte(pBB,iOffset++); palette[i].green = ReadByte(pBB,iOffset++); palette[i].red = ReadByte(pBB,iOffset++); if(!m_bOldBMPFormat) iOffset++; } if (iOffset > m_iOffset) return UT_IE_BOGUSDOCUMENT; png_set_PLTE( m_pPNG, m_pPNGInfo, palette, numClrs ); return UT_OK; }
int spupng_write_png(struct spupng_t *sp, struct eia608_screen* data, png_structp png_ptr, png_infop info_ptr, png_bytep image, png_bytep* row_pointer, unsigned int ww, unsigned int wh) { unsigned int i; if (setjmp(png_jmpbuf(png_ptr))) return 0; png_init_io (png_ptr, sp->fppng); png_set_IHDR (png_ptr, info_ptr, ww, wh, /* bit_depth */ 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_PLTE (png_ptr, info_ptr, palette, sizeof(palette) / sizeof(palette[0])); png_set_tRNS (png_ptr, info_ptr, alpha, sizeof(alpha) / sizeof(alpha[0]), NULL); png_set_gAMA (png_ptr, info_ptr, 1.0 / 2.2); png_write_info (png_ptr, info_ptr); for (i = 0; i < wh; i++) row_pointer[i] = image + i * ww; png_write_image (png_ptr, row_pointer); png_write_end (png_ptr, info_ptr); return 1; }
bool CCImage::_saveImageToPNG(const char * pszFilePath, bool bIsToRGB) { bool bRet = false; do { CC_BREAK_IF(NULL == pszFilePath); FILE *fp; png_structp png_ptr; png_infop info_ptr; png_colorp palette; png_bytep *row_pointers; fp = fopen(pszFilePath, "wb"); CC_BREAK_IF(NULL == fp); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { fclose(fp); break; } info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { fclose(fp); png_destroy_write_struct(&png_ptr, NULL); break; } #if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA) if (setjmp(png_jmpbuf(png_ptr))) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } #endif png_init_io(png_ptr, fp); if (!bIsToRGB && m_bHasAlpha) { png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } else { png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); } palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); row_pointers = (png_bytep *)malloc(m_nHeight * sizeof(png_bytep)); if(row_pointers == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } if (!m_bHasAlpha) { for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 3; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; } else { if (bIsToRGB) { unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3]; if (NULL == pTempData) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); break; } for (int i = 0; i < m_nHeight; ++i) { for (int j = 0; j < m_nWidth; ++j) { pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4]; pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1]; pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2]; } } for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)pTempData + i * m_nWidth * 3; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; CC_SAFE_DELETE_ARRAY(pTempData); } else { for (int i = 0; i < (int)m_nHeight; i++) { row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 4; } png_write_image(png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; } } png_write_end(png_ptr, info_ptr); png_free(png_ptr, palette); palette = NULL; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); bRet = true; } while (0); return bRet; }
int write_bar_graph(FILE *f, double perc, int width, int height, int border, int spacers) { static png_color palette[4] = { { 0, 0, 0}, /* RGB color for border */ {255, 255, 255}, /* RGB color for separators */ {214, 136, 131}, /* RGB color for unfilled part of graph */ {204, 204, 227}, /* RGB color for filled part of graph */ }; int bwidth, bheight; /* Width and height including border */ double frac; int spacer, fspacer; int x, y; int color; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_byte *border_row; png_byte *bar_row; png_byte *bp; int status = 1; /* Assume failure */ bwidth = width + border*2; bheight = height + border*2; border_row = alloca(sizeof(png_byte) * bwidth); bar_row = alloca(sizeof(png_byte) * bwidth); if ( !border_row || !bar_row ) goto barf; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( !png_ptr ) goto barf; info_ptr = png_create_info_struct(png_ptr); if ( !info_ptr ) goto barf; if ( setjmp(png_jmpbuf((png_ptr))) ) { status = 1; goto barf; /* libpng abort */ } png_init_io(png_ptr, f); png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); png_set_IHDR(png_ptr, info_ptr, bwidth, bheight, 2, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_PLTE(png_ptr, info_ptr, palette, 4); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); /* Now we actually produce the data */ /* Generate the border row */ memset(border_row, 0, bwidth); /* Generate the bar row */ bp = bar_row; for ( x = 0 ; x < border ; x++ ) *bp++ = 0; /* Border color */ spacer = 0; for ( x = 1 ; x <= width ; x++ ) { frac = (double)x/(double)width; fspacer = (int)(spacers*frac); if ( x < width && spacer < fspacer ) { color = 1; /* Spacer color */ } else if ( perc < frac ) { color = 3; /* Bar color */ } else { color = 2; /* Background color */ } *bp++ = color; spacer = fspacer; } for ( x = 0 ; x < border ; x++ ) *bp++ = 0; /* Border color */ /* Write output */ for ( y = 0 ; y < border ; y++ ) png_write_row(png_ptr, border_row); for ( y = 0 ; y < height ; y++ ) png_write_row(png_ptr, bar_row); for ( y = 0 ; y < border ; y++ ) png_write_row(png_ptr, border_row); /* Done writing */ png_write_end(png_ptr, info_ptr); status = 0; /* Success! */ barf: /* Jump here on fatal error */ png_destroy_write_struct(&png_ptr, &info_ptr); return status; }
bool MCImageEncodePNG(MCImageIndexedBitmap *p_indexed, IO_handle p_stream, uindex_t &r_bytes_written) { bool t_success = true; MCPNGWriteContext t_context; t_context.stream = p_stream; t_context.byte_count = 0; png_structp t_png_ptr = nil; png_infop t_info_ptr = nil; png_color *t_png_palette = nil; png_byte *t_png_transparency = nil; png_bytep t_data_ptr = nil; uindex_t t_stride = 0; /*init png stuff*/ if (t_success) { t_success = nil != (t_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL)); } if (t_success) t_success = nil != (t_info_ptr = png_create_info_struct(t_png_ptr)); /*in case of png error*/ if (setjmp(png_jmpbuf(t_png_ptr))) t_success = false; if (t_success) png_set_write_fn(t_png_ptr,(png_voidp)&t_context,fakewrite,fakeflush); if (t_success) { png_set_IHDR(t_png_ptr, t_info_ptr, p_indexed->width, p_indexed->height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_gAMA(t_png_ptr, t_info_ptr, 1/MCgamma); } if (t_success) t_success = MCMemoryNewArray(p_indexed->palette_size, t_png_palette); /*create palette for 8 bit*/ if (t_success) { for (uindex_t i = 0; i < p_indexed->palette_size ; i++) { t_png_palette[i].red = p_indexed->palette[i].red >> 8; t_png_palette[i].green = p_indexed->palette[i].green >> 8; t_png_palette[i].blue = p_indexed->palette[i].blue >> 8; } png_set_PLTE(t_png_ptr, t_info_ptr, t_png_palette, p_indexed->palette_size); } if (MCImageIndexedBitmapHasTransparency(p_indexed)) { if (t_success) t_success = MCMemoryAllocate(p_indexed->palette_size, t_png_transparency); if (t_success) { memset(t_png_transparency, 0xFF, p_indexed->palette_size); t_png_transparency[p_indexed->transparent_index] = 0x00; png_set_tRNS(t_png_ptr, t_info_ptr, t_png_transparency, p_indexed->palette_size, NULL); } } if (t_success) png_write_info(t_png_ptr, t_info_ptr); if (t_success) { t_data_ptr = (png_bytep)p_indexed->data; t_stride = p_indexed->stride; } if (t_success) { for (uindex_t i = 0; i < p_indexed->height; i++) { png_write_row(t_png_ptr, t_data_ptr); t_data_ptr += t_stride; } } if (t_success) png_write_end(t_png_ptr, t_info_ptr); if (t_png_ptr != nil) png_destroy_write_struct(&t_png_ptr, &t_info_ptr); if (t_png_palette != nil) MCMemoryDeleteArray(t_png_palette); if (t_png_transparency != nil) MCMemoryDeallocate(t_png_transparency); if (t_success) r_bytes_written = t_context.byte_count; return t_success; }
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); }
static int writePNG(QRcode *qrcode, const char *outfile) { static FILE *fp; // avoid clobbering by setjmp. png_structp png_ptr; png_infop info_ptr; png_colorp palette; png_byte alpha_values[2]; unsigned char *row, *p, *q; int x, y, xx, yy, bit; int realwidth; realwidth = (qrcode->width + margin * 2) * size; row = (unsigned char *)malloc((realwidth + 7) / 8); if(row == NULL) { fprintf(stderr, "Failed to allocate memory.\n"); exit(EXIT_FAILURE); } if(outfile[0] == '-' && outfile[1] == '\0') { fp = stdout; } else { fp = fopen(outfile, "wb"); if(fp == NULL) { fprintf(stderr, "Failed to create file: %s\n", outfile); perror(NULL); exit(EXIT_FAILURE); } } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png_ptr == NULL) { fprintf(stderr, "Failed to initialize PNG writer.\n"); exit(EXIT_FAILURE); } info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { fprintf(stderr, "Failed to initialize PNG write.\n"); exit(EXIT_FAILURE); } if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fprintf(stderr, "Failed to write PNG image.\n"); exit(EXIT_FAILURE); } palette = (png_colorp) malloc(sizeof(png_color) * 2); if(palette == NULL) { fprintf(stderr, "Failed to allocate memory.\n"); exit(EXIT_FAILURE); } palette[0].red = fg_color[0]; palette[0].green = fg_color[1]; palette[0].blue = fg_color[2]; palette[1].red = bg_color[0]; palette[1].green = bg_color[1]; palette[1].blue = bg_color[2]; alpha_values[0] = fg_color[3]; alpha_values[1] = bg_color[3]; png_set_PLTE(png_ptr, info_ptr, palette, 2); png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL); png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, realwidth, realwidth, 1, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_pHYs(png_ptr, info_ptr, dpi * INCHES_PER_METER, dpi * INCHES_PER_METER, PNG_RESOLUTION_METER); png_write_info(png_ptr, info_ptr); /* top margin */ memset(row, 0xff, (realwidth + 7) / 8); for(y=0; y<margin * size; y++) { png_write_row(png_ptr, row); } /* data */ p = qrcode->data; for(y=0; y<qrcode->width; y++) { bit = 7; memset(row, 0xff, (realwidth + 7) / 8); q = row; q += margin * size / 8; bit = 7 - (margin * size % 8); for(x=0; x<qrcode->width; x++) { for(xx=0; xx<size; xx++) { *q ^= (*p & 1) << bit; bit--; if(bit < 0) { q++; bit = 7; } } p++; } for(yy=0; yy<size; yy++) { png_write_row(png_ptr, row); } } /* bottom margin */ memset(row, 0xff, (realwidth + 7) / 8); for(y=0; y<margin * size; y++) { png_write_row(png_ptr, row); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); free(row); free(palette); return 0; }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr; png_infop info_ptr; png_colorp palette = NULL; png_uint_32 width, height; BOOL has_alpha_channel = FALSE; RGBQUAD *pal; // pointer to dib palette int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels int palette_entries; int interlace_type; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if ((dib) && (handle)) { try { // create the chunk manage structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return FALSE; } // allocate/initialize the image information data. info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return FALSE; } // Set error handling. REQUIRED if you aren't supplying your own // error handling functions in the png_create_write_struct() call. if (setjmp(png_jmpbuf(png_ptr))) { // if we get here, we had a problem reading the file png_destroy_write_struct(&png_ptr, &info_ptr); return FALSE; } // init the IO png_set_write_fn(png_ptr, &fio, _WriteProc, _FlushProc); // set physical resolution png_uint_32 res_x = (png_uint_32)FreeImage_GetDotsPerMeterX(dib); png_uint_32 res_y = (png_uint_32)FreeImage_GetDotsPerMeterY(dib); if ((res_x > 0) && (res_y > 0)) { png_set_pHYs(png_ptr, info_ptr, res_x, res_y, PNG_RESOLUTION_METER); } // 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 width = FreeImage_GetWidth(dib); height = FreeImage_GetHeight(dib); pixel_depth = FreeImage_GetBPP(dib); BOOL bInterlaced = FALSE; if( (flags & PNG_INTERLACED) == PNG_INTERLACED) { interlace_type = PNG_INTERLACE_ADAM7; bInterlaced = TRUE; } else { interlace_type = PNG_INTERLACE_NONE; } // set the ZLIB compression level or default to PNG default compression level (ZLIB level = 6) int zlib_level = flags & 0x0F; if((zlib_level >= 1) && (zlib_level <= 9)) { png_set_compression_level(png_ptr, zlib_level); } else if((flags & PNG_Z_NO_COMPRESSION) == PNG_Z_NO_COMPRESSION) { png_set_compression_level(png_ptr, Z_NO_COMPRESSION); } // filtered strategy works better for high color images if(pixel_depth >= 16){ png_set_compression_strategy(png_ptr, Z_FILTERED); png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH); } else { png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); } FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if(image_type == FIT_BITMAP) { // standard image type bit_depth = (pixel_depth > 8) ? 8 : pixel_depth; } else { // 16-bit greyscale or 16-bit RGB(A) bit_depth = 16; } switch (FreeImage_GetColorType(dib)) { case FIC_MINISWHITE: // Invert monochrome files to have 0 as black and 1 as white (no break here) png_set_invert_mono(png_ptr); case FIC_MINISBLACK: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_GRAY, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); break; case FIC_PALETTE: { png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_PALETTE, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set the palette palette_entries = 1 << bit_depth; palette = (png_colorp)png_malloc(png_ptr, palette_entries * sizeof (png_color)); pal = FreeImage_GetPalette(dib); for (int i = 0; i < palette_entries; i++) { palette[i].red = pal[i].rgbRed; palette[i].green = pal[i].rgbGreen; palette[i].blue = pal[i].rgbBlue; } png_set_PLTE(png_ptr, info_ptr, palette, palette_entries); // You must not free palette here, because png_set_PLTE only makes a link to // the palette that you malloced. Wait until you are about to destroy // the png structure. break; } case FIC_RGBALPHA : has_alpha_channel = TRUE; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGBA, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip BGR pixels to RGB if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case FIC_RGB: png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB, interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip BGR pixels to RGB if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case FIC_CMYK: break; } // write possible ICC profile FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib); if (iccProfile->size && iccProfile->data) { png_set_iCCP(png_ptr, info_ptr, "Embedded Profile", 0, (png_const_bytep)iccProfile->data, iccProfile->size); } // write metadata WriteMetadata(png_ptr, info_ptr, dib); // Optional gamma chunk is strongly suggested if you have any guess // as to the correct gamma of the image. // png_set_gAMA(png_ptr, info_ptr, gamma); // set the transparency table if (FreeImage_IsTransparent(dib) && (FreeImage_GetTransparencyCount(dib) > 0)) { png_set_tRNS(png_ptr, info_ptr, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), NULL); } // set the background color if(FreeImage_HasBackgroundColor(dib)) { png_color_16 image_background; RGBQUAD rgbBkColor; FreeImage_GetBackgroundColor(dib, &rgbBkColor); memset(&image_background, 0, sizeof(png_color_16)); image_background.blue = rgbBkColor.rgbBlue; image_background.green = rgbBkColor.rgbGreen; image_background.red = rgbBkColor.rgbRed; image_background.index = rgbBkColor.rgbReserved; png_set_bKGD(png_ptr, info_ptr, &image_background); } // Write the file header information. png_write_info(png_ptr, info_ptr); // write out the image data #ifndef FREEIMAGE_BIGENDIAN if (bit_depth == 16) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif int number_passes = 1; if (bInterlaced) { number_passes = png_set_interlace_handling(png_ptr); } if ((pixel_depth == 32) && (!has_alpha_channel)) { BYTE *buffer = (BYTE *)malloc(width * 3); // transparent conversion to 24-bit // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { for (png_uint_32 k = 0; k < height; k++) { FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width); png_write_row(png_ptr, buffer); } } free(buffer); } else { // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { for (png_uint_32 k = 0; k < height; k++) { png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1)); } } } // It is REQUIRED to call this to finish writing the rest of the file // Bug with png_flush png_write_end(png_ptr, info_ptr); // clean up after the write, and free any memory allocated if (palette) { png_free(png_ptr, palette); } png_destroy_write_struct(&png_ptr, &info_ptr); return TRUE; } catch (const char *text) { FreeImage_OutputMessageProc(s_format_id, text); } } return FALSE; }
/* * Reduce the image type from grayscale(+alpha) or RGB(+alpha) to palette, * if possible. * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. */ png_uint_32 /* PRIVATE */ opng_reduce_to_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_uint_32 result; png_bytepp row_ptr; png_bytep sample_ptr, alpha_row; png_uint_32 height, width, channels, i, j; unsigned int color_type, dest_bit_depth; png_color palette[256]; png_byte trans_alpha[256]; int num_palette, num_trans, index; png_color_16p background; unsigned int gray, red, green, blue, alpha; unsigned int prev_gray, prev_red, prev_green, prev_blue, prev_alpha; opng_debug(1, "in opng_reduce_to_palette"); if (info_ptr->bit_depth != 8) return OPNG_REDUCE_NONE; /* nothing is done in this case */ color_type = info_ptr->color_type; OPNG_ASSERT(!(info_ptr->color_type & PNG_COLOR_MASK_PALETTE)); row_ptr = info_ptr->row_pointers; height = info_ptr->height; width = info_ptr->width; channels = info_ptr->channels; alpha_row = (png_bytep)png_malloc(png_ptr, width); /* Analyze the possibility of this reduction. */ num_palette = num_trans = 0; prev_gray = prev_red = prev_green = prev_blue = prev_alpha = 256; for (i = 0; i < height; ++i, ++row_ptr) { sample_ptr = *row_ptr; opng_get_alpha_row(png_ptr, info_ptr, *row_ptr, alpha_row); if (color_type & PNG_COLOR_MASK_COLOR) { for (j = 0; j < width; ++j, sample_ptr += channels) { red = sample_ptr[0]; green = sample_ptr[1]; blue = sample_ptr[2]; alpha = alpha_row[j]; /* Check the cache first. */ if (red != prev_red || green != prev_green || blue != prev_blue || alpha != prev_alpha) { prev_red = red; prev_green = green; prev_blue = blue; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, alpha, &index) < 0) /* overflow */ { OPNG_ASSERT(num_palette < 0); i = height; /* forced exit from outer loop */ break; } } } } else /* grayscale */ { for (j = 0; j < width; ++j, sample_ptr += channels) { gray = sample_ptr[0]; alpha = alpha_row[j]; /* Check the cache first. */ if (gray != prev_gray || alpha != prev_alpha) { prev_gray = gray; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, gray, gray, gray, alpha, &index) < 0) /* overflow */ { OPNG_ASSERT(num_palette < 0); i = height; /* forced exit from outer loop */ break; } } } } } #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) if ((num_palette >= 0) && (info_ptr->valid & PNG_INFO_bKGD)) { /* bKGD has an alpha-agnostic palette entry. */ background = &info_ptr->background; if (color_type & PNG_COLOR_MASK_COLOR) { red = background->red; green = background->green; blue = background->blue; } else red = green = blue = background->gray; opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, 256, &index); if (index >= 0) background->index = (png_byte)index; } #endif /* Continue only if the uncompressed indexed image (pixels + PLTE + tRNS) * is smaller than the uncompressed RGB(A) image. * Casual overhead (headers, CRCs, etc.) is ignored. * * Compare: * num_pixels * (src_bit_depth * channels - dest_bit_depth) / 8 * vs. * sizeof(PLTE) + sizeof(tRNS) */ if (num_palette >= 0) { OPNG_ASSERT(num_palette > 0 && num_palette <= 256); OPNG_ASSERT(num_trans >= 0 && num_trans <= num_palette); if (num_palette <= 2) dest_bit_depth = 1; else if (num_palette <= 4) dest_bit_depth = 2; else if (num_palette <= 16) dest_bit_depth = 4; else dest_bit_depth = 8; /* Do the comparison in a way that does not cause overflow. */ if (channels * 8 == dest_bit_depth || (3 * num_palette + num_trans) * 8 / (channels * 8 - dest_bit_depth) / width / height >= 1) num_palette = -1; } if (num_palette < 0) /* can't reduce */ { png_free(png_ptr, alpha_row); return OPNG_REDUCE_NONE; } /* Reduce. */ row_ptr = info_ptr->row_pointers; index = -1; prev_red = prev_green = prev_blue = prev_alpha = (unsigned int)(-1); for (i = 0; i < height; ++i, ++row_ptr) { sample_ptr = *row_ptr; opng_get_alpha_row(png_ptr, info_ptr, *row_ptr, alpha_row); if (color_type & PNG_COLOR_MASK_COLOR) { for (j = 0; j < width; ++j, sample_ptr += channels) { red = sample_ptr[0]; green = sample_ptr[1]; blue = sample_ptr[2]; alpha = alpha_row[j]; /* Check the cache first. */ if (red != prev_red || green != prev_green || blue != prev_blue || alpha != prev_alpha) { prev_red = red; prev_green = green; prev_blue = blue; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, alpha, &index) != 0) index = -1; /* this should not happen */ } OPNG_ASSERT(index >= 0); (*row_ptr)[j] = (png_byte)index; } } else /* grayscale */ { for (j = 0; j < width; ++j, sample_ptr += channels) { gray = sample_ptr[0]; alpha = alpha_row[j]; /* Check the cache first. */ if (gray != prev_gray || alpha != prev_alpha) { prev_gray = gray; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, gray, gray, gray, alpha, &index) != 0) index = -1; /* this should not happen */ } OPNG_ASSERT(index >= 0); (*row_ptr)[j] = (png_byte)index; } } } /* Update the image info. */ png_ptr->rowbytes = info_ptr->rowbytes = 0; png_ptr->color_type = info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; png_ptr->channels = info_ptr->channels = 1; png_ptr->pixel_depth = info_ptr->pixel_depth = 8; png_set_PLTE(png_ptr, info_ptr, palette, num_palette); if (num_trans > 0) png_set_tRNS(png_ptr, info_ptr, trans_alpha, num_trans, NULL); /* bKGD (if present) is already updated. */ png_free(png_ptr, alpha_row); result = OPNG_REDUCE_RGB_TO_PALETTE; if (reductions & OPNG_REDUCE_8_TO_4_2_1) result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions); return result; }
/*! * pixWriteStreamPng() * * Input: stream * pix * gamma (use 0.0 if gamma is not defined) * Return: 0 if OK; 1 on error * * Notes: * (1) If called from pixWriteStream(), the stream is positioned * at the beginning of the file. * (2) To do sequential writes of png format images to a stream, * use pixWriteStreamPng() directly. * (3) gamma is an optional png chunk. If no gamma value is to be * placed into the file, use gamma = 0.0. Otherwise, if * gamma > 0.0, its value is written into the header. * (4) The use of gamma in png is highly problematic. For an illuminating * discussion, see: http://hsivonen.iki.fi/png-gamma/ * (5) What is the effect/meaning of gamma in the png file? This * gamma, which we can call the 'source' gamma, is the * inverse of the gamma that was used in enhance.c to brighten * or darken images. The 'source' gamma is supposed to indicate * the intensity mapping that was done at the time the * image was captured. Display programs typically apply a * 'display' gamma of 2.2 to the output, which is intended * to linearize the intensity based on the response of * thermionic tubes (CRTs). Flat panel LCDs have typically * been designed to give a similar response as CRTs (call it * "backward compatibility"). The 'display' gamma is * in some sense the inverse of the 'source' gamma. * jpeg encoders attached to scanners and cameras will lighten * the pixels, applying a gamma corresponding to approximately * a square-root relation of output vs input: * output = input^(gamma) * where gamma is often set near 0.4545 (1/gamma is 2.2). * This is stored in the image file. Then if the display * program reads the gamma, it will apply a display gamma, * typically about 2.2; the product is 1.0, and the * display program produces a linear output. This works because * the dark colors were appropriately boosted by the scanner, * as described by the 'source' gamma, so they should not * be further boosted by the display program. * (6) As an example, with xv and display, if no gamma is stored, * the program acts as if gamma were 0.4545, multiplies this by 2.2, * and does a linear rendering. Taking this as a baseline * brightness, if the stored gamma is: * > 0.4545, the image is rendered lighter than baseline * < 0.4545, the image is rendered darker than baseline * In contrast, gqview seems to ignore the gamma chunk in png. * (7) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16 * and 32. However, it is possible, and in some cases desirable, * to write out a png file using an rgb pix that has 24 bpp. * For example, the open source xpdf SplashBitmap class generates * 24 bpp rgb images. Consequently, we anble writing 24 bpp pix. * To generate such a pix, you can make a 24 bpp pix without data * and assign the data array to the pix; e.g., * pix = pixCreateHeader(w, h, 24); * pixSetData(pix, rgbdata); * See pixConvert32To24() for an example, where we get rgbdata * from the 32 bpp pix. Caution: do not call pixSetPadBits(), * because the alignment is wrong and you may erase part of the * last pixel on each line. */ l_int32 pixWriteStreamPng(FILE *fp, PIX *pix, l_float32 gamma) { char commentstring[] = "Comment"; l_int32 i, j, k; l_int32 wpl, d, cmflag; l_int32 ncolors; l_int32 *rmap, *gmap, *bmap; l_uint32 *data, *ppixel; png_byte bit_depth, color_type; png_uint_32 w, h; png_uint_32 xres, yres; png_bytep *row_pointers; png_bytep rowbuffer; png_structp png_ptr; png_infop info_ptr; png_colorp palette; PIX *pixt; PIXCMAP *cmap; char *text; PROCNAME("pixWriteStreamPng"); if (!fp) return ERROR_INT("stream not open", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); /* Allocate the 2 data structures */ if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL)) == NULL) return ERROR_INT("png_ptr not made", procName, 1); if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return ERROR_INT("info_ptr not made", procName, 1); } /* Set up png setjmp error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return ERROR_INT("internal png error", procName, 1); } png_init_io(png_ptr, fp); /* With best zlib compression (9), get between 1 and 10% improvement * over default (5), but the compression is 3 to 10 times slower. * Our default compression is the zlib default (5). */ png_set_compression_level(png_ptr, var_ZLIB_COMPRESSION); w = pixGetWidth(pix); h = pixGetHeight(pix); d = pixGetDepth(pix); if ((cmap = pixGetColormap(pix))) cmflag = 1; else cmflag = 0; /* Set the color type and bit depth. */ if (d == 32 && var_PNG_WRITE_ALPHA == 1) { bit_depth = 8; color_type = PNG_COLOR_TYPE_RGBA; /* 6 */ cmflag = 0; /* ignore if it exists */ } else if (d == 24 || d == 32) { bit_depth = 8; color_type = PNG_COLOR_TYPE_RGB; /* 2 */ cmflag = 0; /* ignore if it exists */ } else { bit_depth = d; color_type = PNG_COLOR_TYPE_GRAY; /* 0 */ } if (cmflag) color_type = PNG_COLOR_TYPE_PALETTE; /* 3 */ #if DEBUG fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n", cmflag, bit_depth, color_type); #endif /* DEBUG */ png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Store resolution in ppm, if known */ xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5); yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5); if ((xres == 0) || (yres == 0)) png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN); else png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER); if (cmflag) { pixcmapToArrays(cmap, &rmap, &gmap, &bmap); ncolors = pixcmapGetCount(cmap); /* Make and save the palette */ if ((palette = (png_colorp)(CALLOC(ncolors, sizeof(png_color)))) == NULL) return ERROR_INT("palette not made", procName, 1); for (i = 0; i < ncolors; i++) { palette[i].red = (png_byte)rmap[i]; palette[i].green = (png_byte)gmap[i]; palette[i].blue = (png_byte)bmap[i]; } png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors); FREE(rmap); FREE(gmap); FREE(bmap); } /* 0.4545 is treated as the default by some image * display programs (not gqview). A value > 0.4545 will * lighten an image as displayed by xv, display, etc. */ if (gamma > 0.0) png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma); if ((text = pixGetText(pix))) { png_text text_chunk; text_chunk.compression = PNG_TEXT_COMPRESSION_NONE; text_chunk.key = commentstring; text_chunk.text = text; text_chunk.text_length = strlen(text); #ifdef PNG_ITXT_SUPPORTED text_chunk.itxt_length = 0; text_chunk.lang = NULL; text_chunk.lang_key = NULL; #endif png_set_text(png_ptr, info_ptr, &text_chunk, 1); } /* Write header and palette info */ png_write_info(png_ptr, info_ptr); if ((d != 32) && (d != 24)) { /* not rgb color */ /* Generate a temporary pix with bytes swapped. * For a binary image, there are two conditions in * which you must first invert the data for writing png: * (a) no colormap * (b) colormap with BLACK set to 0 * png writes binary with BLACK = 0, unless contradicted * by a colormap. If the colormap has BLACK = "1" * (typ. about 255), do not invert the data. If there * is no colormap, you must invert the data to store * in default BLACK = 0 state. */ if (d == 1 && (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) { pixt = pixInvert(NULL, pix); pixEndianByteSwap(pixt); } else pixt = pixEndianByteSwapNew(pix); if (!pixt) { png_destroy_write_struct(&png_ptr, &info_ptr); return ERROR_INT("pixt not made", procName, 1); } /* Make and assign array of image row pointers */ if ((row_pointers = (png_bytep *)CALLOC(h, sizeof(png_bytep))) == NULL) return ERROR_INT("row-pointers not made", procName, 1); wpl = pixGetWpl(pixt); data = pixGetData(pixt); for (i = 0; i < h; i++) row_pointers[i] = (png_bytep)(data + i * wpl); png_set_rows(png_ptr, info_ptr, row_pointers); /* Transfer the data */ png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); if (cmflag) FREE(palette); FREE(row_pointers); pixDestroy(&pixt); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } /* For rgb, compose and write a row at a time */ data = pixGetData(pix); wpl = pixGetWpl(pix); if (d == 24) { /* See note 7 above: special case of 24 bpp rgb */ for (i = 0; i < h; i++) { ppixel = data + i * wpl; png_write_rows(png_ptr, (png_bytepp)&ppixel, 1); } } else { /* 32 bpp rgb and rgba */ if ((rowbuffer = (png_bytep)CALLOC(w, 4)) == NULL) return ERROR_INT("rowbuffer not made", procName, 1); for (i = 0; i < h; i++) { ppixel = data + i * wpl; for (j = k = 0; j < w; j++) { rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED); rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN); rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE); if (var_PNG_WRITE_ALPHA == 1) rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL); ppixel++; } png_write_rows(png_ptr, &rowbuffer, 1); } FREE(rowbuffer); } png_write_end(png_ptr, info_ptr); if (cmflag) FREE(palette); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; }
void write_png (std::string filename) { FILE* fp; png_structp png_ptr; png_infop info_ptr; png_colorp palette; //png_uint_32 bytes_per_pixel = 1; fp = fopen(filename.c_str (), "wb"); if (fp == NULL) assert (false); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8 /* bitdepth */, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); std::cout << "MAX: " << PNG_MAX_PALETTE_LENGTH << std::endl; for (unsigned int i = 0; i < m_palette.size(); ++i) { palette[i].red = m_palette[i].red; palette[i].green = m_palette[i].green; palette[i].blue = m_palette[i].blue; } /** insert palette converter here */ png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); png_write_info(png_ptr, info_ptr); png_uint_32 height = m_height, width = m_width; png_byte image[height * width /* *bytes_per_pixel */]; png_bytep row_pointers[height]; // fill the image with data for (unsigned int i = 0; i < m_image.size (); ++i) { image[i] = m_image[i]; } for (unsigned int k = 0; k < height; k++) row_pointers[k] = image + k * width /* * bytes_per_pixel*/; png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); png_free(png_ptr, palette); //png_free(png_ptr, trans); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); }
/* Saves an SDL surface to a png file. * TODO: support screen formats. */ int sdl_surface_savepng(SDL_Surface * surf, const char * filename) { png_bytep * rows = NULL; png_colorp pale = NULL; FILE * fout = NULL; png_structp png = NULL; png_infop info = NULL; int colortype; int i = 0; Uint8 * tran = NULL; SDL_PixelFormat * fmt = NULL; SDL_Surface * temp = NULL; if (!surf) { return save_fail("Surface was NULL."); } if (!filename) { return save_fail("Filename was NULL."); } rows = gymalloc(sizeof(png_bytep)*surf->h); if (!rows) { return save_fail("Out of memory."); } for (i = 0; i < surf->h; i++) { rows[i] = ((Uint8 *)surf->pixels) + i*surf->pitch; } /* Create palette and transparency table if needed. */ fmt = surf->format; if (fmt->palette) { pale = malloc(fmt->palette->ncolors * sizeof(png_color)); if (!pale) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Out of memory in saving palette."); } for (i = 0; i < fmt->palette->ncolors; i++) { pale[i].red = fmt->palette->colors[i].r; pale[i].green = fmt->palette->colors[i].g; pale[i].blue = fmt->palette->colors[i].b; } if (surf->flags & SDL_SRCCOLORKEY) { tran = malloc(fmt->palette->ncolors * sizeof(Uint8)); if(!tran) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Out of memory in saving palette transparency."); } for (i = 0; i < fmt->palette->ncolors; i++) { tran[i] = (((unsigned)i) == fmt->colorkey) ? 255 : 0; } } } fout = fopen(filename, "wb"); if(!fout) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Couldn't open file for writing."); } png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Couldn't create png_structp"); } info = png_create_info_struct(png); if (!info) { savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Couldn't create png_infop"); } /* libpng rudely uses longjump to terminate on errors. This in turns causes warning of pissbli clobered variables. Could it suck more? */ if (setjmp(png->jmpbuf)) { /* This give a warning, but it seems to be unavoidable. */ savepng_done(rows, fout, png, info, temp, pale, tran); return save_fail("Error writing png file."); } /* Set file pointer. */ png_init_io(png, fout); colortype = sdl_surface_pngcolortype(surf); png_set_IHDR(png, info, surf->w, surf->h, 8, colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Write palette if needed. */ if(pale) { png_set_PLTE(png, info, pale, fmt->palette->ncolors); } /* Write transparency table if needed. */ if (tran) { png_set_tRNS(png, info, tran, fmt->palette->ncolors, NULL); } /* Write the image. */ png_write_info(png, info); png_set_packing(png); if(SDL_MUSTLOCK(surf)) { SDL_LockSurface(surf); } png_write_image(png, rows); if(SDL_MUSTLOCK(surf)) { SDL_UnlockSurface(surf); } png_write_end(png, info); /* Clean up. */ savepng_done(rows, fout, png, info, temp, pale, tran); return 0; }
void write_header( const View& view ) { using png_rw_info_t = detail::png_write_support < typename channel_type<typename get_pixel_type<View>::type>::type, typename color_space_type<View>::type >; // 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 png_set_IHDR( get_struct() , get_info() , static_cast< png_image_width::type >( view.width() ) , static_cast< png_image_height::type >( view.height() ) , static_cast< png_bitdepth::type >( png_rw_info_t::_bit_depth ) , static_cast< png_color_type::type >( png_rw_info_t::_color_type ) , _info._interlace_method , _info._compression_type , _info._filter_method ); #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_cie_colors ) { png_set_cHRM( get_struct() , get_info() , _info._white_x , _info._white_y , _info._red_x , _info._red_y , _info._green_x , _info._green_y , _info._blue_x , _info._blue_y ); } if( _info._valid_file_gamma ) { png_set_gAMA( get_struct() , get_info() , _info._file_gamma ); } #else if( _info._valid_cie_colors ) { png_set_cHRM_fixed( get_struct() , get_info() , _info._white_x , _info._white_y , _info._red_x , _info._red_y , _info._green_x , _info._green_y , _info._blue_x , _info._blue_y ); } if( _info._valid_file_gamma ) { png_set_gAMA_fixed( get_struct() , get_info() , _info._file_gamma ); } #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_icc_profile ) { #if PNG_LIBPNG_VER_MINOR >= 5 png_set_iCCP( get_struct() , get_info() , const_cast< png_charp >( _info._icc_name.c_str() ) , _info._iccp_compression_type , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) ) , _info._profile_length ); #else png_set_iCCP( get_struct() , get_info() , const_cast< png_charp >( _info._icc_name.c_str() ) , _info._iccp_compression_type , const_cast< png_charp >( & (_info._profile.front()) ) , _info._profile_length ); #endif } if( _info._valid_intent ) { png_set_sRGB( get_struct() , get_info() , _info._intent ); } if( _info._valid_palette ) { png_set_PLTE( get_struct() , get_info() , const_cast< png_colorp >( &_info._palette.front() ) , _info._num_palette ); } if( _info._valid_background ) { png_set_bKGD( get_struct() , get_info() , const_cast< png_color_16p >( &_info._background ) ); } if( _info._valid_histogram ) { png_set_hIST( get_struct() , get_info() , const_cast< png_uint_16p >( &_info._histogram.front() ) ); } if( _info._valid_offset ) { png_set_oFFs( get_struct() , get_info() , _info._offset_x , _info._offset_y , _info._off_unit_type ); } if( _info._valid_pixel_calibration ) { std::vector< const char* > params( _info._num_params ); for( std::size_t i = 0; i < params.size(); ++i ) { params[i] = _info._params[ i ].c_str(); } png_set_pCAL( get_struct() , get_info() , const_cast< png_charp >( _info._purpose.c_str() ) , _info._X0 , _info._X1 , _info._cal_type , _info._num_params , const_cast< png_charp >( _info._units.c_str() ) , const_cast< png_charpp >( ¶ms.front() ) ); } if( _info._valid_resolution ) { png_set_pHYs( get_struct() , get_info() , _info._res_x , _info._res_y , _info._phy_unit_type ); } if( _info._valid_significant_bits ) { png_set_sBIT( get_struct() , get_info() , const_cast< png_color_8p >( &_info._sig_bits ) ); } #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_scale_factors ) { png_set_sCAL( get_struct() , get_info() , this->_info._scale_unit , this->_info._scale_width , this->_info._scale_height ); } #else #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED if( _info._valid_scale_factors ) { png_set_sCAL_fixed( get_struct() , get_info() , this->_info._scale_unit , this->_info._scale_width , this->_info._scale_height ); } #else if( _info._valid_scale_factors ) { png_set_sCAL_s( get_struct() , get_info() , this->_info._scale_unit , const_cast< png_charp >( this->_info._scale_width.c_str() ) , const_cast< png_charp >( this->_info._scale_height.c_str() ) ); } #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER if( _info._valid_text ) { std::vector< png_text > texts( _info._num_text ); for( std::size_t i = 0; i < texts.size(); ++i ) { png_text pt; pt.compression = _info._text[i]._compression; pt.key = const_cast< png_charp >( this->_info._text[i]._key.c_str() ); pt.text = const_cast< png_charp >( this->_info._text[i]._text.c_str() ); pt.text_length = _info._text[i]._text.length(); texts[i] = pt; } png_set_text( get_struct() , get_info() , &texts.front() , _info._num_text ); } if( _info._valid_modification_time ) { png_set_tIME( get_struct() , get_info() , const_cast< png_timep >( &_info._mod_time ) ); } if( _info._valid_transparency_factors ) { int sample_max = ( 1u << _info._bit_depth ); /* libpng doesn't reject a tRNS chunk with out-of-range samples */ if( !( ( _info._color_type == PNG_COLOR_TYPE_GRAY && (int) _info._trans_values[0].gray > sample_max ) || ( _info._color_type == PNG_COLOR_TYPE_RGB &&( (int) _info._trans_values[0].red > sample_max || (int) _info._trans_values[0].green > sample_max || (int) _info._trans_values[0].blue > sample_max ) ) ) ) { //@todo Fix that once reading transparency values works /* png_set_tRNS( get_struct() , get_info() , trans , num_trans , trans_values ); */ } } // Compression Levels - valid values are [0,9] png_set_compression_level( get_struct() , _info._compression_level ); png_set_compression_mem_level( get_struct() , _info._compression_mem_level ); png_set_compression_strategy( get_struct() , _info._compression_strategy ); png_set_compression_window_bits( get_struct() , _info._compression_window_bits ); png_set_compression_method( get_struct() , _info._compression_method ); png_set_compression_buffer_size( get_struct() , _info._compression_buffer_size ); #ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED // Dithering if( _info._set_dithering ) { png_set_dither( get_struct() , &_info._dithering_palette.front() , _info._dithering_num_palette , _info._dithering_maximum_colors , &_info._dithering_histogram.front() , _info._full_dither ); } #endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED // Filter if( _info._set_filter ) { png_set_filter( get_struct() , 0 , _info._filter ); } // Invert Mono if( _info._invert_mono ) { png_set_invert_mono( get_struct() ); } // True Bits if( _info._set_true_bits ) { png_set_sBIT( get_struct() , get_info() , &_info._true_bits.front() ); } // sRGB Intent if( _info._set_srgb_intent ) { png_set_sRGB( get_struct() , get_info() , _info._srgb_intent ); } // Strip Alpha if( _info._strip_alpha ) { png_set_strip_alpha( get_struct() ); } // Swap Alpha if( _info._swap_alpha ) { png_set_swap_alpha( get_struct() ); } png_write_info( get_struct() , get_info() ); }