static gboolean ico_write_png (FILE *fp, gint32 layer, gint32 depth) { png_structp png_ptr; png_infop info_ptr; png_byte **row_pointers; gint i, rowstride; gint width, height; gint num_colors_used; guchar *palette; guchar *buf; row_pointers = NULL; palette = NULL; buf = NULL; width = gimp_drawable_width (layer); height = gimp_drawable_height (layer); png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( !png_ptr ) return FALSE; info_ptr = png_create_info_struct (png_ptr); if ( !info_ptr ) { png_destroy_write_struct (&png_ptr, NULL); return FALSE; } if (setjmp (png_jmpbuf (png_ptr))) { png_destroy_write_struct (&png_ptr, &info_ptr); if ( row_pointers ) g_free (row_pointers); if (palette) g_free (palette); if (buf) g_free (buf); return FALSE; } ico_image_get_reduced_buf (layer, depth, &num_colors_used, &palette, &buf); png_init_io (png_ptr, fp); png_set_IHDR (png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info (png_ptr, info_ptr); rowstride = ico_rowstride (width, 32); row_pointers = g_new (png_byte*, height); for (i = 0; i < height; i++) { row_pointers[i] = buf + rowstride * i; } png_write_image (png_ptr, row_pointers); row_pointers = NULL; png_write_end (png_ptr, info_ptr); png_destroy_write_struct (&png_ptr, &info_ptr); g_free (row_pointers); g_free (palette); g_free (buf); return TRUE; }
PyObject * save_png_fast_progressive (char *filename, int w, int h, bool has_alpha, PyObject *data_generator, bool write_legacy_png) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; PyObject * result = NULL; int bpc; FILE * fp = NULL; PyObject *iterator = NULL; /* TODO: try if this silliness helps #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) 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 */ bpc = 8; fp = fopen(filename, "wb"); if (!fp) { PyErr_SetFromErrno(PyExc_IOError); //PyErr_Format(PyExc_IOError, "Could not open PNG file for writing: %s", filename); goto cleanup; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, png_write_error_callback, NULL); if (!png_ptr) { PyErr_SetString(PyExc_MemoryError, "png_create_write_struct() failed"); goto cleanup; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { PyErr_SetString(PyExc_MemoryError, "png_create_info_struct() failed"); goto cleanup; } if (setjmp(png_jmpbuf(png_ptr))) { goto cleanup; } png_init_io(png_ptr, fp); png_set_IHDR (png_ptr, info_ptr, w, h, bpc, has_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (! write_legacy_png) { // Internal data is sRGB by the time it gets here. // Explicitly save with the recommended chunks to advertise that fact. png_set_sRGB_gAMA_and_cHRM (png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); } // default (all filters enabled): 1350ms, 3.4MB //png_set_filter(png_ptr, 0, PNG_FILTER_NONE); // 790ms, 3.8MB //png_set_filter(png_ptr, 0, PNG_FILTER_PAETH); // 980ms, 3.5MB png_set_filter(png_ptr, 0, PNG_FILTER_SUB); // 760ms, 3.4MB //png_set_compression_level(png_ptr, 0); // 0.49s, 32MB //png_set_compression_level(png_ptr, 1); // 0.98s, 9.6MB png_set_compression_level(png_ptr, 2); // 1.08s, 9.4MB //png_set_compression_level(png_ptr, 9); // 18.6s, 9.3MB png_write_info(png_ptr, info_ptr); if (!has_alpha) { // input array format format is rgbu png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); } { iterator = PyObject_GetIter(data_generator); if (!iterator) goto cleanup; int y = 0; while (y < h) { int rows; PyObject * arr = PyIter_Next(iterator); if (PyErr_Occurred()) goto cleanup; assert(arr); // iterator should have data assert(PyArray_ISALIGNED(arr)); assert(PyArray_NDIM(arr) == 3); assert(PyArray_DIM(arr, 1) == w); assert(PyArray_DIM(arr, 2) == 4); // rgbu assert(PyArray_TYPE(arr) == NPY_UINT8); assert(PyArray_STRIDE(arr, 1) == 4); assert(PyArray_STRIDE(arr, 2) == 1); rows = PyArray_DIM(arr, 0); assert(rows > 0); y += rows; png_bytep p = (png_bytep)PyArray_DATA(arr); for (int row=0; row<rows; row++) { png_write_row (png_ptr, p); p += PyArray_STRIDE(arr, 0); } Py_DECREF(arr); } assert(y == h); PyObject * obj = PyIter_Next(iterator); assert(!obj); // iterator should be finished if (PyErr_Occurred()) goto cleanup; } png_write_end (png_ptr, NULL); result = Py_BuildValue("{}"); cleanup: if (iterator) Py_DECREF(iterator); if (info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) fclose(fp); return result; }
bool PNGImageFileType::write(const Image *OSG_PNG_ARG(pImage ), std::ostream &OSG_PNG_ARG(os ), const std::string &OSG_PNG_ARG(mimetype)) { #ifdef OSG_WITH_PNG png_structp png_ptr; png_infop info_ptr; if(pImage->getDimension() < 1 || pImage->getDimension() > 2) { FWARNING(("PNGImageFileType::write: invalid dimension %d!\n", pImage->getDimension())); return false; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, &errorOutput, &warningOutput); if(png_ptr == NULL) return false; /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); return false; } /* set up the output handlers */ png_set_write_fn(png_ptr, &os, &osWriteFunc, &osFlushFunc); /* This is the hard way */ /* 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 */ Int32 ctype; switch(pImage->getPixelFormat()) { case Image::OSG_L_PF: ctype = PNG_COLOR_TYPE_GRAY; break; case Image::OSG_LA_PF: ctype = PNG_COLOR_TYPE_GRAY_ALPHA; break; #if defined(GL_BGR) || defined(GL_BGR_EXT) case Image::OSG_BGR_PF: #endif case Image::OSG_RGB_PF: ctype = PNG_COLOR_TYPE_RGB; break; #if defined(GL_BGRA) || defined(GL_BGRA_EXT) case Image::OSG_BGRA_PF: #endif case Image::OSG_RGBA_PF: ctype = PNG_COLOR_TYPE_RGB_ALPHA; break; default: FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n", pImage->getPixelFormat())); png_destroy_write_struct(&png_ptr, NULL); return false; } Int32 bit_depth; switch(pImage->getDataType()) { case Image::OSG_UINT8_IMAGEDATA: bit_depth = 8; break; case Image::OSG_UINT16_IMAGEDATA: bit_depth = 16; break; default: FWARNING (("Invalid pixeldepth, cannot store data\n")); return false; }; png_set_IHDR(png_ptr, info_ptr, pImage->getWidth(), pImage->getHeight(), bit_depth,ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // set resolution png supports only meter per pixel, // so we do a conversion from dpi with some rounding. png_uint_32 res_x = png_uint_32(pImage->getResX()); png_uint_32 res_y = png_uint_32(pImage->getResY()); if(pImage->getResUnit() == Image::OSG_RESUNIT_INCH) { res_x = png_uint_32((pImage->getResX() * 39.37007874f) < 0.0f ? (pImage->getResX() * 39.37007874f) - 0.5f : (pImage->getResX() * 39.37007874f) + 0.5f); res_y = png_uint_32((pImage->getResY() * 39.37007874f) < 0.0f ? (pImage->getResY() * 39.37007874f) - 0.5f : (pImage->getResY() * 39.37007874f) + 0.5f); } png_set_pHYs(png_ptr, info_ptr, res_x, res_y, PNG_RESOLUTION_METER); #if 0 /* optional significant bit chunk */ /* if we are dealing with a grayscale image then */ sig_bit.gray = true_bit_depth; /* otherwise, if we are dealing with a color image then */ sig_bit.red = true_red_bit_depth; sig_bit.green = true_green_bit_depth; sig_bit.blue = true_blue_bit_depth; /* if the image has an alpha channel then */ sig_bit.alpha = true_alpha_bit_depth; png_set_sBIT(png_ptr, info_ptr, sig_bit); /* 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); /* Optionally write comments into the image */ text_ptr[0].key = "Title"; text_ptr[0].text = "Mona Lisa"; text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[1].key = "Author"; text_ptr[1].text = "Leonardo DaVinci"; text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[2].key = "Description"; text_ptr[2].text = "<long text>"; text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; #ifdef PNG_iTXt_SUPPORTED text_ptr[0].lang = NULL; text_ptr[1].lang = NULL; text_ptr[2].lang = NULL; #endif png_set_text(png_ptr, info_ptr, text_ptr, 3); #endif /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ /* note that if sRGB is present the gAMA and cHRM chunks must be ignored * on read and must be written in accordance with the sRGB profile */ /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); #if BYTE_ORDER == LITTLE_ENDIAN if (bit_depth == 16) png_set_swap(png_ptr); #endif #if 0 /* invert monochrome pixels */ png_set_invert_mono(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, &sig_bit); /* pack pixels into bytes */ png_set_packing(png_ptr); /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels). The second parameter is not used. */ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); /* swap bytes of 16-bit files to most significant byte first */ png_set_swap(png_ptr); /* swap bits of 1, 2, 4 bit packed pixel formats */ png_set_packswap(png_ptr); #endif if(pImage->getPixelFormat() == Image::OSG_BGR_PF || pImage->getPixelFormat() == Image::OSG_BGRA_PF ) { /* flip BGR pixels to RGB */ png_set_bgr(png_ptr); /* swap location of alpha bytes from ARGB to RGBA */ png_set_swap_alpha(png_ptr); } /* The easiest way to write the image (you may have a different memory * layout, however, so choose what fits your needs best). You need to * use the first method if you aren't handling interlacing yourself. */ png_bytep *row_pointers = new png_bytep [pImage->getHeight()]; for(Int32 k = 0; k < pImage->getHeight(); k++) { row_pointers[k] = (const_cast<UInt8 *>(pImage->getData())) + (pImage->getHeight() - 1 - k) * pImage->getWidth() * pImage->getBpp(); } /* write out the entire image data in one call */ png_write_image(png_ptr, row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); /* clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); delete [] row_pointers; /* that's it */ return true; #else SWARNING << getMimeType() << " write is not compiled into the current binary " << endLog; return false; #endif }
template<typename T> void encodeImageToPNG (typename std::vector<T>& image_arg, size_t width_arg, size_t height_arg, int image_format_arg, typename std::vector<uint8_t>& pngData_arg, int png_level_arg) { png_structp png_ptr; png_infop info_ptr; volatile int channels; if (image_arg.size () ==0) return; // Get amount of channels switch (image_format_arg) { case PNG_COLOR_TYPE_GRAY: channels = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: channels = 2; break; case PNG_COLOR_TYPE_RGB: channels = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: channels = 4; break; default: channels = 0; break; } // Ensure valid input array assert (image_arg.size () == width_arg*height_arg*channels); // Initialize write structure png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); assert (png_ptr && "creating png_create_write_structpng_create_write_struct failed"); // Initialize info structure info_ptr = png_create_info_struct (png_ptr); assert (info_ptr && "Could not allocate info struct"); // Setup Exception handling setjmp(png_jmpbuf(png_ptr)); // reserve memory for output data (300kB) pngData_arg.clear (); pngData_arg.reserve (300 * 1024); // Define I/O methods png_set_write_fn (png_ptr, reinterpret_cast<void*> (&pngData_arg), user_write_data, user_flush_data); // Define zlib compression level if (png_level_arg >= 0) { png_set_compression_level (png_ptr, png_level_arg); } else { png_set_compression_level (png_ptr, Z_DEFAULT_COMPRESSION); } // Write header png_set_IHDR (png_ptr, info_ptr, width_arg, height_arg, sizeof(T) * 8, image_format_arg, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info (png_ptr, info_ptr); // Write image data size_t y; for (y = 0; y < height_arg; y++) { png_write_row (png_ptr, reinterpret_cast<png_bytep> (&image_arg[y * width_arg * channels])); } // End write png_write_end (png_ptr, 0); if (info_ptr) png_free_data (png_ptr, info_ptr, PNG_FREE_ALL, -1); if (png_ptr) png_destroy_write_struct (&png_ptr, 0); }
void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, float fps, Bit8u * data, Bit8u * pal) { #if (C_SSHOT) Bitu i; Bit8u doubleRow[SCALER_MAXWIDTH*4]; Bitu countWidth = width; if (flags & CAPTURE_FLAG_DBLH) height *= 2; if (flags & CAPTURE_FLAG_DBLW) width *= 2; if (height > SCALER_MAXHEIGHT) return; if (width > SCALER_MAXWIDTH) return; if (CaptureState & CAPTURE_IMAGE) { png_structp png_ptr; png_infop info_ptr; png_color palette[256]; CaptureState &= ~CAPTURE_IMAGE; /* Open the actual file */ FILE * fp=OpenCaptureFile("Screenshot",".png"); if (!fp) goto skip_shot; /* First try to allocate the png structures */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); if (!png_ptr) goto skip_shot; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)NULL); goto skip_shot; } /* Finalize the initing of png library */ png_init_io(png_ptr, fp); png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); /* set other zlib parameters */ 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); png_set_compression_buffer_size(png_ptr, 8192); if (bpp==8) { png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); for (i=0;i<256;i++) { palette[i].red=pal[i*4+0]; palette[i].green=pal[i*4+1]; palette[i].blue=pal[i*4+2]; } png_set_PLTE(png_ptr, info_ptr, palette,256); } else { png_set_bgr( png_ptr ); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } #ifdef PNG_TEXT_SUPPORTED int fields = 1; png_text text[1]; const char* text_s = "DOSBox " VERSION; size_t strl = strlen(text_s); char* ptext_s = new char[strl + 1]; strcpy(ptext_s, text_s); char software[9] = { 'S','o','f','t','w','a','r','e',0}; text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].key = software; text[0].text = ptext_s; png_set_text(png_ptr, info_ptr, text, fields); #endif png_write_info(png_ptr, info_ptr); #ifdef PNG_TEXT_SUPPORTED delete [] ptext_s; #endif for (i=0;i<height;i++) { void *rowPointer; void *srcLine; if (flags & CAPTURE_FLAG_DBLH) srcLine=(data+(i >> 1)*pitch); else srcLine=(data+(i >> 0)*pitch); rowPointer=srcLine; switch (bpp) { case 8: if (flags & CAPTURE_FLAG_DBLW) { for (Bitu x=0;x<countWidth;x++) doubleRow[x*2+0] = doubleRow[x*2+1] = ((Bit8u *)srcLine)[x]; rowPointer = doubleRow; } break; case 15: if (flags & CAPTURE_FLAG_DBLW) { for (Bitu x=0;x<countWidth;x++) { Bitu pixel = ((Bit16u *)srcLine)[x]; doubleRow[x*6+0] = doubleRow[x*6+3] = ((pixel& 0x001f) * 0x21) >> 2; doubleRow[x*6+1] = doubleRow[x*6+4] = ((pixel& 0x03e0) * 0x21) >> 7; doubleRow[x*6+2] = doubleRow[x*6+5] = ((pixel& 0x7c00) * 0x21) >> 12; } } else { for (Bitu x=0;x<countWidth;x++) { Bitu pixel = ((Bit16u *)srcLine)[x]; doubleRow[x*3+0] = ((pixel& 0x001f) * 0x21) >> 2; doubleRow[x*3+1] = ((pixel& 0x03e0) * 0x21) >> 7; doubleRow[x*3+2] = ((pixel& 0x7c00) * 0x21) >> 12; } } rowPointer = doubleRow; break; case 16: if (flags & CAPTURE_FLAG_DBLW) { for (Bitu x=0;x<countWidth;x++) { Bitu pixel = ((Bit16u *)srcLine)[x]; doubleRow[x*6+0] = doubleRow[x*6+3] = ((pixel& 0x001f) * 0x21) >> 2; doubleRow[x*6+1] = doubleRow[x*6+4] = ((pixel& 0x07e0) * 0x41) >> 9; doubleRow[x*6+2] = doubleRow[x*6+5] = ((pixel& 0xf800) * 0x21) >> 13; } } else { for (Bitu x=0;x<countWidth;x++) {
static DVector<uint8_t> _lossless_pack_png(const Image& p_image) { Image img = p_image; if (img.get_format() > Image::FORMAT_INDEXED_ALPHA) img.decompress(); ERR_FAIL_COND_V(img.get_format() > Image::FORMAT_INDEXED_ALPHA, DVector<uint8_t>()); png_structp png_ptr; png_infop info_ptr; png_bytep * row_pointers; /* initialize stuff */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); ERR_FAIL_COND_V(!png_ptr,DVector<uint8_t>()); info_ptr = png_create_info_struct(png_ptr); ERR_FAIL_COND_V(!info_ptr,DVector<uint8_t>()); if (setjmp(png_jmpbuf(png_ptr))) { ERR_FAIL_V(DVector<uint8_t>()); } DVector<uint8_t> ret; ret.push_back('P'); ret.push_back('N'); ret.push_back('G'); ret.push_back(' '); png_set_write_fn(png_ptr,&ret,_write_png_data,NULL); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) { ERR_FAIL_V(DVector<uint8_t>()); } int pngf=0; int pngb=8; int cs=0; switch(img.get_format()) { case Image::FORMAT_GRAYSCALE: { pngf=PNG_COLOR_TYPE_GRAY; cs=1; } break; case Image::FORMAT_GRAYSCALE_ALPHA: { pngf=PNG_COLOR_TYPE_GRAY_ALPHA; cs=2; } break; case Image::FORMAT_RGB: { pngf=PNG_COLOR_TYPE_RGB; cs=3; } break; case Image::FORMAT_RGBA: { pngf=PNG_COLOR_TYPE_RGB_ALPHA; cs=4; } break; default: { if (img.detect_alpha()) { img.convert(Image::FORMAT_RGBA); pngf=PNG_COLOR_TYPE_RGB_ALPHA; cs=4; } else { img.convert(Image::FORMAT_RGB); pngf=PNG_COLOR_TYPE_RGB; cs=3; } } } int w = img.get_width(); int h = img.get_height(); png_set_IHDR(png_ptr, info_ptr, w,h, 8, pngf, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); /* write bytes */ if (setjmp(png_jmpbuf(png_ptr))) { ERR_FAIL_V(DVector<uint8_t>()); } DVector<uint8_t>::Read r = img.get_data().read(); row_pointers = (png_bytep*)memalloc(sizeof(png_bytep)*h); for(int i=0;i<h;i++) { row_pointers[i]=(png_bytep)&r[i*w*cs]; } png_write_image(png_ptr, row_pointers); memfree(row_pointers); /* end write */ if (setjmp(png_jmpbuf(png_ptr))) { ERR_FAIL_V(DVector<uint8_t>()); } png_write_end(png_ptr, NULL); return ret; }
static int save_png(SDL_Surface* surface, char *path) { int w = surface->w; int h = surface->h; unsigned char * pix = (unsigned char *)surface->pixels; unsigned char writeBuffer[1024 * 3]; FILE *f = fopen(path,"wb"); if(!f) return 0; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) { fclose(f); return 0; } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_write_struct(&png_ptr,NULL); fclose(f); return 0; } png_init_io(png_ptr,f); png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr,info_ptr); unsigned char *b = writeBuffer; int sizeX = w; int sizeY = h; int y; int x; unsigned short *p = (unsigned short *)pix; for(y = 0; y < sizeY; y++) { for(x = 0; x < sizeX; x++) { unsigned short v = p[x]; *b++ = ((v & systemRedMask ) >> systemRedShift ) << 3; // R *b++ = ((v & systemGreenMask) >> systemGreenShift) << 2; // G *b++ = ((v & systemBlueMask ) >> systemBlueShift ) << 3; // B } p += surface->pitch / 2; png_write_row(png_ptr,writeBuffer); b = writeBuffer; } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); return 1; }
int convertToPNG(AbstractFile* imageWrapper, const unsigned int* key, const unsigned int* iv, const char* png) { AbstractFile* imageFile; FILE *fp = fopen(png, "wb"); if(!fp) return -1; if(key != NULL) { imageFile = openAbstractFile2(imageWrapper, key, iv); } else { imageFile = openAbstractFile(imageWrapper); } InfoIBootIM* info = (InfoIBootIM*) (imageFile->data); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngError, pngWarn); if (!png_ptr) { return -1; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return -1; } png_init_io(png_ptr, fp); int color_type; int bytes_per_pixel; if(info->header.format == IBOOTIM_ARGB) { XLOG(3, "ARGB"); color_type = PNG_COLOR_TYPE_RGB_ALPHA; bytes_per_pixel = 4; } else if(info->header.format == IBOOTIM_GREY) { XLOG(3, "Grayscale"); color_type = PNG_COLOR_TYPE_GRAY_ALPHA; bytes_per_pixel = 2; } else { XLOG(3, "Unknown color type!"); } png_set_IHDR(png_ptr, info_ptr, info->header.width, info->header.height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_bgr(png_ptr); png_set_invert_alpha(png_ptr); png_write_info(png_ptr, info_ptr); void* imageBuffer = malloc(imageFile->getLength(imageFile)); imageFile->read(imageFile, imageBuffer, imageFile->getLength(imageFile)); png_bytepp row_pointers = (png_bytepp) malloc(sizeof(png_bytep) * info->header.height); int i; for(i = 0; i < png_get_image_height(png_ptr, info_ptr); i++) { row_pointers[i] = imageBuffer + (info->header.width * bytes_per_pixel * i); } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, NULL); free(imageBuffer); return 0; }
void SavePNG(const char *name, const byte * pic, int width, int height, int numBytes, qboolean flip) { png_structp png; png_infop info; int i; int row_stride; byte *buffer; byte *row; png_bytep *row_pointers; png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) return; // Allocate/initialize the image information data info = png_create_info_struct(png); if(!info) { png_destroy_write_struct(&png, (png_infopp) NULL); return; } png_compressed_size = 0; buffer = ri.Hunk_AllocateTempMemory(width * height * numBytes); // set error handling if(setjmp(png_jmpbuf(png))) { ri.Hunk_FreeTempMemory(buffer); png_destroy_write_struct(&png, &info); return; } png_set_write_fn(png, buffer, png_write_data, png_flush_data); switch ( numBytes ) { default: png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); break; case 3: png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); break; case 2: png_set_IHDR( png, info, width, height, 8, PNG_COLOR_TYPE_GA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); break; case 1: png_set_IHDR( png, info, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); break; } // write the file header information png_write_info(png, info); row_pointers = ri.Hunk_AllocateTempMemory(height * sizeof(png_bytep)); if(setjmp(png_jmpbuf(png))) { ri.Hunk_FreeTempMemory(row_pointers); ri.Hunk_FreeTempMemory(buffer); png_destroy_write_struct(&png, &info); return; } row_stride = width * numBytes; row = (byte *)pic + (height - 1) * row_stride; if(flip) { for(i = height - 1; i >= 0; i--) { row_pointers[i] = row; row -= row_stride; } } else { for(i = 0; i < height; i++) { row_pointers[i] = row; row -= row_stride; } } png_write_image(png, row_pointers); png_write_end(png, info); // clean up after the write, and free any memory allocated png_destroy_write_struct(&png, &info); ri.Hunk_FreeTempMemory(row_pointers); ri.FS_WriteFile(name, buffer, png_compressed_size); ri.Hunk_FreeTempMemory(buffer); }
/************************************************************************** Save given buffer type to file. **************************************************************************/ bool savePngInternal(const char *filename, unsigned char *pixels, int w, int h, int bitdepth, int color_type) { png_structp pngp; png_infop infop; int y; FILE *fp; png_bytep *row_pointers; int const bytes = bitdepth / 8; if (filename == NULL || *filename == '\0' || pixels == NULL) { return false; } if (!(fp = fopen(filename, "wb"))) { debug(LOG_ERROR, "%s won't open for writing!", filename); return false; } pngp = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngp) { debug(LOG_ERROR, "fgl_save_pixmap: Failed to create PNG write struct"); fclose(fp); return false; } infop = png_create_info_struct(pngp); if (!infop) { debug(LOG_ERROR, "fgl_save_pixmap: Failed to create PNG info struct"); fclose(fp); png_destroy_write_struct(&pngp, NULL); return false; } if (setjmp(png_jmpbuf(pngp))) { debug(LOG_ERROR, "fgl_save_pixmap: Failed to initialize IO during PNG save"); fclose(fp); png_destroy_write_struct(&pngp, NULL); return false; } png_init_io(pngp, fp); /* write header */ if (setjmp(png_jmpbuf(pngp))) { debug(LOG_ERROR, "fgl_save_pixmap: Failed to write PNG header"); fclose(fp); png_destroy_write_struct(&pngp, NULL); return false; } png_set_IHDR(pngp, infop, w, h, bitdepth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(pngp, infop); /* Create pointers to each row of the data, as libpng wants it */ row_pointers = malloc(sizeof(png_bytep) * h); for (y = 0; y < h; y++) { row_pointers[y] = pixels + (y * w * bytes); } if (setjmp(png_jmpbuf(pngp))) { debug(LOG_ERROR, "fgl_save_pixmap: Failed to write PNG body"); fclose(fp); png_destroy_write_struct(&pngp, NULL); return false; } png_write_image(pngp, row_pointers); if (setjmp(png_jmpbuf(pngp))) { debug(LOG_ERROR, "fgl_save_pixmap: Failed to finalize PNG"); fclose(fp); png_destroy_write_struct(&pngp, NULL); return false; } png_write_end(pngp, NULL); free(row_pointers); fclose(fp); png_destroy_write_struct(&pngp, NULL); return true; }
int write_PNG(char *filename, int interlace, char borfb) { //hardcore theft from fbgrab.c /* * fbgrab - takes screenshots using the framebuffer. * * (C) Gunnar Monell <*****@*****.**> 2002 * * This program is free Software, see the COPYING file * and is based on Stephan Beyer's <*****@*****.**> FBShot * (C) 2000. * * For features and differences, read the manual page. * * This program has been checked with "splint +posixlib" without * warnings. Splint is available from http://www.splint.org/ . * Patches and enhancements of fbgrab have to fulfill this too. */ png_uint_32 i; int bit_depth=0, color_type; png_uint_32 uheight, uwidth; uheight = (png_uint_32)height; uwidth = (png_uint_32)width; png_bytep row_pointers[uheight]; png_structp png_ptr; png_infop info_ptr; FILE *outfile = fopen(filename, "wb"); interlace = PNG_INTERLACE_NONE; //printf ("%d, %d\n", uheight, uwidth); //well, either from the buffer or the framebuffer... //yih, gotta clean this one up, reallyyyyy // if (borfb == 0) for (i=0; i<uheight; i++) row_pointers[i] = (unsigned char *)(fbp + (BPP*Ox) + (Oy + i) * 1 * (finfo.line_length/*uwidth+10*/)); if (borfb == 1) for (i=0; i<uheight; i++) row_pointers[i] = (unsigned char *)(tmp_buf + (BPP*Ox) + (Oy + i) * 1 * (finfo.line_length/*uwidth+10*/)); if (!outfile){ fprintf (stderr, "Error: Couldn't fopen %s.\n", filename); return -1; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, (png_error_ptr) NULL, (png_error_ptr) NULL); if (!png_ptr){ fprintf(stderr,"Error: Couldn't create PNG write struct."); return -1; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr){ png_destroy_write_struct(&png_ptr, (png_infopp) NULL); fprintf(stderr, "Error: Couldn't create PNG info struct."); return -1; } if (setjmp(png_jmpbuf(png_ptr))){ fclose(outfile); png_destroy_write_struct(&png_ptr, &info_ptr); return -2; } png_init_io(png_ptr, outfile); //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); bit_depth = 8; color_type = PNG_COLOR_TYPE_RGB_ALPHA; png_set_IHDR(png_ptr, info_ptr, uwidth, uheight, bit_depth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); //png_set_packing(png_ptr); png_set_invert_alpha(png_ptr); // //png_set function must be after set_IHDR //according to libpng-manual png_set_filter(png_ptr, 0, PNG_FILTER_NONE); png_set_filler(png_ptr, 0 , PNG_FILLER_BEFORE); png_set_bgr(png_ptr); png_write_info(png_ptr, info_ptr); //printf ("Now writing PNG file\n"); png_write_image(png_ptr, row_pointers); //png_write_rows(png_ptr, row_pointers, uheight); png_write_end(png_ptr, info_ptr); //puh, done, now freeing memory... png_destroy_write_struct(&png_ptr, &info_ptr); if (outfile != NULL) (void) fclose(outfile); //printf("Done writing...\n"); return 0; }
bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, const QString &description, int off_x_in, int off_y_in) { QPoint offset = image.offset(); int off_x = off_x_in + offset.x(); int off_y = off_y_in + offset.y(); png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { return false; } png_set_error_fn(png_ptr, 0, 0, qt_png_warning); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, 0); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return false; } int quality = quality_in; if (quality >= 0) { if (quality > 9) { qWarning("PNG: Quality %d out of range", quality); quality = 9; } png_set_compression_level(png_ptr, quality); } png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn); int color_type = 0; if (image.colorCount()) { if (image.isGrayscale()) color_type = PNG_COLOR_TYPE_GRAY; else color_type = PNG_COLOR_TYPE_PALETTE; } else if (image.format() == QImage::Format_Grayscale8) color_type = PNG_COLOR_TYPE_GRAY; else if (image.hasAlphaChannel()) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), image.depth() == 1 ? 1 : 8, // per channel color_type, 0, 0, 0); // sets #channels if (gamma != 0.0) { png_set_gAMA(png_ptr, info_ptr, 1.0/gamma); } if (image.format() == QImage::Format_MonoLSB) png_set_packswap(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { // Paletted int num_palette = qMin(256, image.colorCount()); png_color palette[256]; png_byte trans[256]; int num_trans = 0; for (int i=0; i<num_palette; i++) { QRgb rgba=image.color(i); palette[i].red = qRed(rgba); palette[i].green = qGreen(rgba); palette[i].blue = qBlue(rgba); trans[i] = qAlpha(rgba); if (trans[i] < 255) { num_trans = i+1; } } png_set_PLTE(png_ptr, info_ptr, palette, num_palette); if (num_trans) { png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0); } } // Swap ARGB to RGBA (normal PNG format) before saving on // BigEndian machines if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { png_set_swap_alpha(png_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless if (QSysInfo::ByteOrder == QSysInfo::LittleEndian && image.format() != QImage::Format_RGB888) { png_set_bgr(png_ptr); } if (off_x || off_y) { png_set_oFFs(png_ptr, info_ptr, off_x, off_y, PNG_OFFSET_PIXEL); } if (frames_written > 0) png_set_sig_bytes(png_ptr, 8); if (image.dotsPerMeterX() > 0 || image.dotsPerMeterY() > 0) { png_set_pHYs(png_ptr, info_ptr, image.dotsPerMeterX(), image.dotsPerMeterY(), PNG_RESOLUTION_METER); } set_text(image, png_ptr, info_ptr, description); png_write_info(png_ptr, info_ptr); if (image.depth() != 1) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_RGB && image.format() != QImage::Format_RGB888) png_set_filler(png_ptr, 0, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); if (looping >= 0 && frames_written == 0) { uchar data[13] = "NETSCAPE2.0"; // 0123456789aBC data[0xB] = looping%0x100; data[0xC] = looping/0x100; png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFx"), data, 13); } if (ms_delay >= 0 || disposal!=Unspecified) { uchar data[4]; data[0] = disposal; data[1] = 0; data[2] = (ms_delay/10)/0x100; // hundredths data[3] = (ms_delay/10)%0x100; png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFg"), data, 4); } int height = image.height(); int width = image.width(); switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: case QImage::Format_Grayscale8: case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: { png_bytep* row_pointers = new png_bytep[height]; for (int y=0; y<height; y++) row_pointers[y] = const_cast<png_bytep>(image.constScanLine(y)); png_write_image(png_ptr, row_pointers); delete [] row_pointers; } break; default: { QImage::Format fmt = image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32; QImage row; png_bytep row_pointers[1]; for (int y=0; y<height; y++) { row = image.copy(0, y, width, 1).convertToFormat(fmt); row_pointers[0] = const_cast<png_bytep>(row.constScanLine(0)); png_write_rows(png_ptr, row_pointers, 1); } } break; } png_write_end(png_ptr, info_ptr); frames_written++; png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
/* Write "bitmap" to a PNG file specified by "path"; returns 0 on success, non-zero on error. */ int save_png_to_file(const char *path) { FILE *fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; size_t x, y; /* "status" contains the return value of this function. At first it is set to a value which means 'failure'. When the routine has finished its work, it is set to a value which means 'success'. */ int status = -1; /* The following number is set by trial and error only. I cannot see where it it is documented in the libpng manual. */ int pixel_size = 3; int depth = 8; /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* para el manejo de errores */ fp = fopen(path, "wb"); if (!fp) { return status; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return status; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return status; } /* Set up error handling. */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return status; } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /* Set image attributes. */ png_set_IHDR(png_ptr, info_ptr, H_RES, //bitmap->width, V_RES, // bitmap->height, depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Initialize rows of PNG. */ png_byte **row_pointers = NULL; row_pointers = png_malloc(png_ptr, V_RES * sizeof (png_byte *)); //recorro todo el eje vertical(y) para ir obteniendo las filas for (y = 0; y < V_RES; y++) { //obtener el inverso de la fila int y_temp = (V_RES - y) - 1; png_byte *row = png_malloc(png_ptr, sizeof (uint8_t) * H_RES * pixel_size); row_pointers[y_temp] = row; //recorro todos los puntos for (x = 0; x < H_RES; x++) { //pixel_t * pixel = pixel_at(bitmap, x, y); *row++ = (int) (frameBuffer[x][y].r * 255); *row++ = (int) (frameBuffer[x][y].g * 255); *row++ = (int) (frameBuffer[x][y].b * 255); } } /* Write the image data to "fp". */ png_init_io(png_ptr, fp); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); /* The routine has successfully written the file, so we set "status" to a value which indicates success. */ status = 0; for (y = 0; y < V_RES; y++) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); }
int writepng_init(mainprog_info *mainprog_ptr) { AMJU_CALL_STACK; png_structp png_ptr; /* note: temporary variables! */ png_infop info_ptr; int color_type, interlace_type; /* could also replace libpng warning-handler (final NULL), but no need: */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, writepng_error_handler, NULL); if (!png_ptr) return 4; /* out of memory */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); return 4; /* out of memory */ } /* setjmp() must be called in every function that calls a PNG-writing * 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 go: */ if (setjmp(mainprog_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, &info_ptr); return 2; } /* make sure outfile is (re)opened in BINARY mode */ png_init_io(png_ptr, mainprog_ptr->outfile); /* set the compression levels--in general, always want to leave filtering * turned on (except for palette images) and allow all of the filters, * which is the default; want 32K zlib window, unless entire image buffer * is 16K or smaller (unknown here)--also the default; usually want max * compression (NOT the default); and remaining compression flags should * be left alone */ png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); /* >> this is default for no filtering; Z_FILTERED is default otherwise: png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); >> these are all defaults: png_set_compression_mem_level(png_ptr, 8); png_set_compression_window_bits(png_ptr, 15); png_set_compression_method(png_ptr, 8); */ /* set the image parameters appropriately */ if (mainprog_ptr->pnmtype == 5) color_type = PNG_COLOR_TYPE_GRAY; else if (mainprog_ptr->pnmtype == 6) color_type = PNG_COLOR_TYPE_RGB; else if (mainprog_ptr->pnmtype == 8) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else { png_destroy_write_struct(&png_ptr, &info_ptr); return 11; } interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height, mainprog_ptr->sample_depth, color_type, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (mainprog_ptr->gamma > 0.0) png_set_gAMA(png_ptr, info_ptr, mainprog_ptr->gamma); if (mainprog_ptr->have_bg) { /* we know it's RGBA, not gray+alpha */ png_color_16 background; background.red = mainprog_ptr->bg_red; background.green = mainprog_ptr->bg_green; background.blue = mainprog_ptr->bg_blue; png_set_bKGD(png_ptr, info_ptr, &background); } if (mainprog_ptr->have_time) { png_time modtime; png_convert_from_time_t(&modtime, mainprog_ptr->modtime); png_set_tIME(png_ptr, info_ptr, &modtime); } if (mainprog_ptr->have_text) { png_text text[6]; int num_text = 0; if (mainprog_ptr->have_text & TEXT_TITLE) { text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; text[num_text].key = (char*)"Title"; text[num_text].text = mainprog_ptr->title; ++num_text; } if (mainprog_ptr->have_text & TEXT_AUTHOR) { text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; text[num_text].key = (char*)"Author"; text[num_text].text = mainprog_ptr->author; ++num_text; } if (mainprog_ptr->have_text & TEXT_DESC) { text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; text[num_text].key = (char*)"Description"; text[num_text].text = mainprog_ptr->desc; ++num_text; } if (mainprog_ptr->have_text & TEXT_COPY) { text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; text[num_text].key = (char*)"Copyright"; text[num_text].text = mainprog_ptr->copyright; ++num_text; } if (mainprog_ptr->have_text & TEXT_EMAIL) { text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; text[num_text].key = (char*)"E-mail"; text[num_text].text = mainprog_ptr->email; ++num_text; } if (mainprog_ptr->have_text & TEXT_URL) { text[num_text].compression = PNG_TEXT_COMPRESSION_NONE; text[num_text].key = (char*)"URL"; text[num_text].text = mainprog_ptr->url; ++num_text; } png_set_text(png_ptr, info_ptr, text, num_text); } /* write all chunks up to (but not including) first IDAT */ png_write_info(png_ptr, info_ptr); /* if we wanted to write any more text info *after* the image data, we * would set up text struct(s) here and call png_set_text() again, with * just the new data; png_set_tIME() could also go here, but it would * have no effect since we already called it above (only one tIME chunk * allowed) */ /* set up the transformations: for now, just pack low-bit-depth pixels * into bytes (one, two or four pixels per byte) */ png_set_packing(png_ptr); /* png_set_shift(png_ptr, &sig_bit); to scale low-bit-depth values */ /* make sure we save our pointers for use in writepng_encode_image() */ mainprog_ptr->png_ptr = png_ptr; mainprog_ptr->info_ptr = info_ptr; /* OK, that's all we need to do for now; return happy */ return 0; }
void Mesh::generateHeightmap(const char* filename) { // Shoot rays down from a point just above the max Y position of the mesh. // Compute ray-triangle intersection tests against the ray and this mesh to // generate heightmap data. Vector3 rayOrigin(0, bounds.max.y + 10, 0); Vector3 rayDirection(0, -1, 0); Vector3 intersectionPoint; int minX = (int)ceil(bounds.min.x); int maxX = (int)floor(bounds.max.x); int minZ = (int)ceil(bounds.min.z); int maxZ = (int)floor(bounds.max.z); int width = maxX - minX + 1; int height = maxZ - minZ + 1; float* heights = new float[width * height]; int index = 0; float minHeight = FLT_MAX; float maxHeight = FLT_MIN; for (int z = minZ; z <= maxZ; z++) { rayOrigin.z = (float)z; for (int x = minX; x <= maxX; x++) { float h; rayOrigin.x = (float)x; if (intersect(rayOrigin, rayDirection, vertices, parts, &intersectionPoint)) { h = intersectionPoint.y; } else { h = 0; fprintf(stderr, "Warning: Heightmap triangle intersection failed for (%d, %d).\n", x, z); } if (h < minHeight) minHeight = h; if (h > maxHeight) maxHeight = h; heights[index++] = h; } } // Normalize the max height value maxHeight = maxHeight - minHeight; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep row = NULL; FILE* fp = fopen(filename, "wb"); if (fp == NULL) { fprintf(stderr, "Error: Failed to open file for writing: %s\n", filename); goto error; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fprintf(stderr, "Error: Write struct creation failed: %s\n", filename); goto error; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fprintf(stderr, "Error: Info struct creation failed: %s\n", filename); goto error; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); // Allocate memory for a single row of image data row = (png_bytep)malloc(3 * width * sizeof(png_byte)); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // Write height value normalized between 0-255 (between min and max height) float h = heights[y*width + x]; float nh = (h - minHeight) / maxHeight; png_byte b = (png_byte)(nh * 255.0f); int pos = x*3; row[pos] = row[pos+1] = row[pos+2] = b; } png_write_row(png_ptr, row); } png_write_end(png_ptr, NULL); DEBUGPRINT_VARG("> Saved heightmap: %s\n", filename); error: if (heights) delete[] heights; if (fp) fclose(fp); if (row) free(row); if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); }
int enc_png(char *data,g2int width,g2int height,g2int nbits,char *pngbuf) { int color_type; g2int j,bytes,pnglen,bit_depth; png_structp png_ptr; png_infop info_ptr; // png_bytep *row_pointers[height]; png_bytep **row_pointers; png_stream write_io_ptr; /* create and initialize png_structs */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); if (!png_ptr) return (-1); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)NULL); return (-2); } /* Set Error callback */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return (-3); } /* Initialize info for writing PNG stream to memory */ write_io_ptr.stream_ptr=(png_voidp)pngbuf; write_io_ptr.stream_len=0; /* Set new custom write functions */ png_set_write_fn(png_ptr,(png_voidp)&write_io_ptr,(png_rw_ptr)user_write_data, (png_flush_ptr)user_flush_data); /* png_init_io(png_ptr, fptr); */ /* png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */ /* Set the image size, colortype, filter type, etc... */ /* printf("SAGTsettingIHDR %d %d %d\n",width,height,bit_depth); */ bit_depth=nbits; color_type=PNG_COLOR_TYPE_GRAY; if (nbits == 24 ) { bit_depth=8; color_type=PNG_COLOR_TYPE_RGB; } else if (nbits == 32 ) { bit_depth=8; color_type=PNG_COLOR_TYPE_RGB_ALPHA; } png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Put image data into the PNG info structure */ /*bytes=bit_depth/8;*/ bytes=nbits/8; row_pointers=malloc(height*sizeof(png_bytep)); for (j=0;j<height;j++) row_pointers[j]=(png_bytep *)(data+(j*width*bytes)); png_set_rows(png_ptr, info_ptr, (png_bytepp)row_pointers); /* Do the PNG encoding, and write out PNG stream */ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); /* Clean up */ png_destroy_write_struct(&png_ptr, &info_ptr); free(row_pointers); pnglen=write_io_ptr.stream_len; return pnglen; }
/* 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 } }
int icns_image_to_png(icns_image_t *image, icns_size_t *dataSizeOut, icns_byte_t **dataPtrOut) { int width = 0; int height = 0; int image_channels = 0; int image_pixel_depth = 0; int mask_channels = 0; png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; int i, j; if(image == NULL) { icns_print_err("icns_image_to_png: Image is NULL!\n"); return ICNS_STATUS_NULL_PARAM; } if(dataSizeOut == NULL) { icns_print_err("icns_image_to_png: Data size NULL!\n"); return ICNS_STATUS_NULL_PARAM; } if(dataPtrOut == NULL) { icns_print_err("icns_image_to_png: Data ref is NULL!\n"); return ICNS_STATUS_NULL_PARAM; } if (image->pngFilename) { FILE *fp = fopen(image->pngFilename, "rb"); if (fp) { fseek(fp, 0, SEEK_END); *dataSizeOut = ftell(fp); fseek(fp, 0, SEEK_SET); *dataPtrOut = malloc(*dataSizeOut); if (fread(*dataPtrOut, 1, *dataSizeOut, fp)) { return ICNS_STATUS_OK; } } } #ifdef ICNS_DEBUG printf("Encoding PNG image...\n"); #endif width = image->imageWidth; height = image->imageHeight; image_channels = image->imageChannels; image_pixel_depth = image->imagePixelDepth; png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fprintf (stderr, "PNG error: cannot allocate libpng main struct\n"); return ICNS_STATUS_NO_MEMORY; } info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { fprintf (stderr, "PNG error: cannot allocate libpng info struct\n"); png_destroy_write_struct (&png_ptr, (png_infopp) NULL); return ICNS_STATUS_NO_MEMORY; } icns_png_io_ref io_data = { NULL, 0, 0 }; png_set_write_fn(png_ptr, (void *)&io_data, &icns_png_write_memory, NULL); png_set_filter(png_ptr, 0, PNG_FILTER_NONE); png_set_IHDR (png_ptr, info_ptr, width, height, image_pixel_depth, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info (png_ptr, info_ptr); if(image_pixel_depth < 8) png_set_packing (png_ptr); row_pointers = (png_bytep*)malloc(sizeof(png_bytep)*height); if (row_pointers == NULL) { fprintf (stderr, "PNG error: unable to allocate row_pointers\n"); } else { for (i = 0; i < height; i++) { if ((row_pointers[i] = (png_bytep)malloc(width*image_channels)) == NULL) { fprintf (stderr, "PNG error: unable to allocate rows\n"); for (j = 0; j < i; j++) free(row_pointers[j]); free(row_pointers); return ICNS_STATUS_NO_MEMORY; } for(j = 0; j < width; j++) { icns_uint32_t *src_pixel = (icns_uint32_t*)&(image->imageData[i*width*image_channels+j*image_channels]); icns_uint32_t *dst_pixel = (icns_uint32_t*)&(row_pointers[i][j*image_channels]); *dst_pixel = *src_pixel; } } } png_write_image (png_ptr,row_pointers); png_write_end (png_ptr, info_ptr); *dataSizeOut = io_data.offset; *dataPtrOut = io_data.data; png_destroy_write_struct (&png_ptr, &info_ptr); for (j = 0; j < height; j++) free(row_pointers[j]); free(row_pointers); return ICNS_STATUS_OK; }
int GImageWrite_Png(GImage *gi, FILE *fp, int progressive) { struct _GImage *base = gi->list_len==0?gi->u.image:gi->u.images[0]; png_structp png_ptr; png_infop info_ptr; png_byte **rows; int i; int bit_depth; int color_type; int num_palette; png_bytep trans_alpha = NULL; png_color_16p trans_color = NULL; png_colorp palette = NULL; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, user_error_fn, user_warning_fn); if (!png_ptr) { return(false); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return(false); } #if (PNG_LIBPNG_VER < 10500) if (setjmp(png_ptr->jmpbuf)) #else if (setjmp(*png_set_longjmp_fn(png_ptr, longjmp, sizeof (jmp_buf)))) #endif { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return(false); } png_init_io(png_ptr, fp); bit_depth = 8; num_palette = base->clut==NULL?2:base->clut->clut_len; if ( base->image_type==it_index || base->image_type==it_bitmap ) { color_type = PNG_COLOR_TYPE_PALETTE; if ( num_palette<=2 ) bit_depth=1; else if ( num_palette<=4 ) bit_depth=2; else if ( num_palette<=16 ) bit_depth=4; } else { color_type = PNG_COLOR_TYPE_RGB; if ( base->image_type == it_rgba ) color_type = PNG_COLOR_TYPE_RGB_ALPHA; } png_set_IHDR(png_ptr, info_ptr, base->width, base->height, bit_depth, color_type, progressive, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if ( base->image_type==it_index || base->image_type==it_bitmap ) { palette = (png_color *) galloc(num_palette*sizeof(png_color)); if ( base->clut==NULL ) { palette[0].red = palette[0].green = palette[0].blue = 0; palette[1].red = palette[1].green = palette[1].blue = 0xff; } else { for ( i=0; i<num_palette; ++i ) { long col = base->clut->clut[i]; palette[i].red = COLOR_RED(col); palette[i].green = COLOR_GREEN(col); palette[i].blue = COLOR_BLUE(col); } } png_set_PLTE(png_ptr, info_ptr, palette, num_palette); if ( num_palette<=16 ) png_set_packing(png_ptr); if ( base->trans!=-1 ) { trans_alpha = (png_bytep) galloc(1); trans_alpha[0] = base->trans; } } else { if ( base->trans!=-1 ) { trans_color = (png_color_16p) galloc(sizeof(png_color_16)); trans_color->red = COLOR_RED(base->trans); trans_color->green = COLOR_GREEN(base->trans); trans_color->blue = COLOR_BLUE(base->trans); } } if ( base->trans!=-1 ) { png_set_tRNS(png_ptr, info_ptr, trans_alpha, 1, trans_color); } png_write_info(png_ptr, info_ptr); if (color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, '\0', PNG_FILLER_BEFORE); rows = (png_byte **) galloc(base->height*sizeof(png_byte *)); for ( i=0; i<base->height; ++i ) rows[i] = (png_byte *) (base->data + i*base->bytes_per_line); png_write_image(png_ptr,rows); png_write_end(png_ptr, info_ptr); if ( trans_alpha!=NULL ) gfree(trans_alpha); if ( trans_color!=NULL ) gfree(trans_color); if ( palette!=NULL ) gfree(palette); png_destroy_write_struct(&png_ptr, &info_ptr); gfree(rows); return( 1 ); }
void take_screenshot(FILE *fb_in, FILE *fb_out) { int fb; char imgbuf[0x10000]; struct fb_var_screeninfo vinfo; png_structp png; png_infop info; unsigned int r,c,rowlen; unsigned int bytespp,offset; fb = fileno(fb_in); if(fb < 0) { ALOGE("failed to open framebuffer\n"); return; } fb_in = fdopen(fb, "r"); if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) { ALOGE("failed to get framebuffer info\n"); return; } fcntl(fb, F_SETFD, FD_CLOEXEC); png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) { ALOGE("failed png_create_write_struct\n"); fclose(fb_in); return; } png_init_io(png, fb_out); info = png_create_info_struct(png); if (info == NULL) { ALOGE("failed png_create_info_struct\n"); png_destroy_write_struct(&png, NULL); fclose(fb_in); return; } if (setjmp(png_jmpbuf(png))) { ALOGE("failed png setjmp\n"); png_destroy_write_struct(&png, NULL); fclose(fb_in); return; } bytespp = vinfo.bits_per_pixel / 8; png_set_IHDR(png, info, vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png, info); rowlen=vinfo.xres * bytespp; if (rowlen > sizeof(imgbuf)) { ALOGE("crazy rowlen: %d\n", rowlen); png_destroy_write_struct(&png, NULL); fclose(fb_in); return; } offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp; fseek(fb_in, offset, SEEK_SET); for(r=0; r<vinfo.yres; r++) { int len = fread(imgbuf, 1, rowlen, fb_in); if (len <= 0) break; png_write_row(png, (png_bytep)imgbuf); } png_write_end(png, info); fclose(fb_in); png_destroy_write_struct(&png, NULL); }
int write_png(image_t* img, const char* file_name) { size_t x, y; png_structp png_ptr; png_infop info_ptr; png_byte** row_pointers; int depth = 8; int pixel_size = 3; /* init the file and structs */ FILE* fp = fopen(file_name, "wb"); if (!fp) { return fail(fp, "Failed to open file for writing"); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { png_destroy_write_struct(&png_ptr, &info_ptr); return fail(fp, "png_create_write_struct failed"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, &info_ptr); return fail(fp, "png_create_info_struct failed"); } /* setup error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return fail(fp, "error"); } /* set image attributes */ png_set_IHDR(png_ptr, info_ptr, img->width, img->height, depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* init rows */ row_pointers = png_malloc(png_ptr, sizeof(png_byte*) * img->height); for (y = 0; y < img->height; ++y) { png_byte* row = png_malloc(png_ptr, sizeof(uint8_t) * img->width * pixel_size); row_pointers[y] = row; for (x = 0; x < img->width; ++x) { pixel_t* pixel = pixel_at(img, x, y); *row++ = pixel->red; *row++ = pixel->green; *row++ = pixel->blue; } } /* write data to file */ png_init_io(png_ptr, fp); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); /* cleanup */ for (y = 0; y < img->height; y++) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return 0; }
int img_save_png( t_image *image) { FILE *fp = fopen( image->id.name, "wb"); png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 bytes_per_row; png_byte **row_pointers = NULL; int x, y; int bytes_per_pixel; int COLOR_TYPE; unsigned char *bitmap = image->vlst->data; switch( image->color_type) { case( IMG_RGB): if( image->alpha) { COLOR_TYPE = PNG_COLOR_TYPE_RGBA; bytes_per_pixel=4; } else { COLOR_TYPE = PNG_COLOR_TYPE_RGB; bytes_per_pixel=3; } break; case( IMG_GRAYSCALE): if( image->alpha) { COLOR_TYPE = PNG_COLOR_TYPE_GRAY_ALPHA; bytes_per_pixel=2; } else { COLOR_TYPE = PNG_COLOR_TYPE_GRAY; bytes_per_pixel=1; } break; case( IMG_BITMAP): printf("[PNG] Color_type not implemented\n"); return 0; break; case IMG_COLOR: printf("[PNG] Color_type not set\n"); return 0; break; } if (fp == NULL) return -1; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return -1; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); fclose(fp); return -1; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return -1; } png_set_IHDR( png_ptr, // struct ptr info_ptr, // info ptr image->width, // in px image->height, // in px 8, // bit depth aka color depth, bits per color [ 1 | 2 | 4 | 8 | 16 ] COLOR_TYPE, // PNG_COLOR_TYPE_[ GRAY | GRAY_ALPHA | PALETTE | RGB | RGB_ALPHA ] or PNG_COLOR_MASK_[ PALETTE | COLOR | ALPHA ] PNG_INTERLACE_NONE, // or PNG_INTERLACE_ADAM7 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); bytes_per_row = image->width * bytes_per_pixel; row_pointers = png_malloc(png_ptr, image->height * sizeof(png_byte *)); for (y = image->height-1 ; y >= 0 ; --y) { unsigned char *row = png_malloc(png_ptr, sizeof(unsigned char) * bytes_per_row); row_pointers[y] = (png_byte *)row; for (x = 0; x < image->width; ++x) { if( image->alpha) { *row++=*bitmap++; *row++=*bitmap++; *row++=*bitmap++; *row++=*bitmap++; } else { *row++=*bitmap++; *row++=*bitmap++; *row++=*bitmap++; } } } png_init_io(png_ptr, fp); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); for (y = 0; y < image->height; y++) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return 0; }
void WritePng(char *path, struct Image *image) { FILE *fp = fopen(path, "wb"); if (fp == NULL) FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) FATAL_ERROR("Failed to create PNG write struct.\n"); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) FATAL_ERROR("Failed to create PNG info struct.\n"); if (setjmp(png_jmpbuf(png_ptr))) FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path); png_init_io(png_ptr, fp); if (setjmp(png_jmpbuf(png_ptr))) FATAL_ERROR("Error writing header for \"%s\".\n", path); int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY; png_set_IHDR(png_ptr, info_ptr, image->width, image->height, image->bitDepth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (image->hasPalette) { SetPngPalette(png_ptr, info_ptr, &image->palette); if (image->hasTransparency) { png_byte trans = 0; png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0); } } png_write_info(png_ptr, info_ptr); png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); if (row_pointers == NULL) FATAL_ERROR("Failed to allocate row pointers.\n"); int rowbytes = png_get_rowbytes(png_ptr, info_ptr); for (int i = 0; i < image->height; i++) row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes)); if (setjmp(png_jmpbuf(png_ptr))) FATAL_ERROR("Error writing \"%s\".\n", path); png_write_image(png_ptr, row_pointers); if (setjmp(png_jmpbuf(png_ptr))) FATAL_ERROR("Error ending write of \"%s\".\n", path); png_write_end(png_ptr, NULL); fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); free(row_pointers); }
static inline bool caerFrameEventPNGCompress(uint8_t **outBuffer, size_t *outSize, uint16_t *inBuffer, int32_t xSize, int32_t ySize, enum caer_frame_event_color_channels channels) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_byte **row_pointers = NULL; // Initialize the write struct. png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { return (false); } // Initialize the info struct. info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); return (false); } // Set up error handling. if (setjmp(png_jmpbuf(png_ptr))) { if (row_pointers != NULL) { png_free(png_ptr, row_pointers); } png_destroy_write_struct(&png_ptr, &info_ptr); return (false); } // Set image attributes. png_set_IHDR(png_ptr, info_ptr, (png_uint_32) xSize, (png_uint_32) ySize, 16, caerFrameEventColorToLibPNG(channels), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // Handle endianness of 16-bit depth pixels correctly. // PNG assumes big-endian, our Frame Event is always little-endian. png_set_swap(png_ptr); // Initialize rows of PNG. row_pointers = png_malloc(png_ptr, (size_t) ySize * sizeof(png_byte *)); if (row_pointers == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); return (false); } for (size_t y = 0; y < (size_t) ySize; y++) { row_pointers[y] = (png_byte *) &inBuffer[y * (size_t) xSize * channels]; } // Set write function to buffer one. struct mem_encode state = { .buffer = NULL, .size = 0 }; png_set_write_fn(png_ptr, &state, &caerLibPNGWriteBuffer, NULL); // Actually write the image data. png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); // Free allocated memory for rows. png_free(png_ptr, row_pointers); // Destroy main structs. png_destroy_write_struct(&png_ptr, &info_ptr); // Pass out buffer with resulting PNG image. *outBuffer = state.buffer; *outSize = state.size; return (true); } #endif static size_t compressEventPacket(outputCommonState state, caerEventPacketHeader packet, size_t packetSize) { // Data compression technique 1: serialize timestamps for event types that tend to repeat them a lot. // Currently, this means polarity events. if ((state->format & 0x01) && caerEventPacketHeaderGetEventType(packet) == POLARITY_EVENT) { // Search for runs of at least 3 events with the same timestamp, and convert them to a special // sequence: leave first event unchanged, but mark its timestamp as special by setting the // highest bit (bit 31) to one (it is forbidden for timestamps in memory to have that bit set for // signed-integer-only language compatibility). Then, for the second event, change its timestamp // to a 4-byte integer saying how many more events will follow afterwards with this same timestamp // (this is used for decoding), so only their data portion will be given. Then follow with those // event's data, back to back, with their timestamps removed. // So let's assume there are 6 events with TS=1234. In memory this looks like this: // E1(data,ts), E2(data,ts), E3(data,ts), E4(data,ts), E5(data,ts), E6(data,ts) // After timestamp serialization compression step: // E1(data,ts|0x80000000), E2(data,4), E3(data), E4(data), E5(data), E5(data) // This change is only in the data itself, not in the packet headers, so that we can still use the // eventCapacity and eventSize fields to calculate memory allocation when doing decompression. // As such, to correctly interpret this data, the Format flags must be correctly set. All current // file or network formats do specify those as mandatory in their headers, so we can rely on that. // Also all event types where this kind of thing makes any sense do have the timestamp as their last // data member in their struct, so we can use that information, stored in tsOffset header field, // together with eventSize, to come up with a generic implementation applicable to all other event // types that satisfy this condition of TS-as-last-member (so we can use that offset as event size). // When this is enabled, it requires full iteration thorough the whole event packet, both at // compression and at decompression time. size_t currPacketOffset = CAER_EVENT_PACKET_HEADER_SIZE; // Start here, no change to header. int32_t eventSize = caerEventPacketHeaderGetEventSize(packet); int32_t eventTSOffset = caerEventPacketHeaderGetEventTSOffset(packet); int32_t lastTS = -1; int32_t currTS = -1; size_t tsRun = 0; bool doMemMove = false; // Initially don't move memory, until we actually shrink the size. for (int32_t caerIteratorCounter = 0; caerIteratorCounter <= caerEventPacketHeaderGetEventNumber(packet); caerIteratorCounter++) { // Iterate until one element past the end, to flush the last run. In that particular case, // we don't get a new element or TS, as we'd be past the end of the array. if (caerIteratorCounter < caerEventPacketHeaderGetEventNumber(packet)) { void *caerIteratorElement = caerGenericEventGetEvent(packet, caerIteratorCounter); currTS = caerGenericEventGetTimestamp(caerIteratorElement, packet); if (currTS == lastTS) { // Increase size of run of same TS events currently being seen. tsRun++; continue; } } // TS are different, at this point look if the last run was long enough // and if it makes sense to compress. It does starting with 3 events. if (tsRun >= 3) { // First event to remains there, we set its TS highest bit. uint8_t *firstEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun--); caerGenericEventSetTimestamp(firstEvent, packet, caerGenericEventGetTimestamp(firstEvent, packet) | I32T(0x80000000)); // Now use second event's timestamp for storing how many further events. uint8_t *secondEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun--); caerGenericEventSetTimestamp(secondEvent, packet, I32T(tsRun)); // Is at least 1. // Finally move modified memory where it needs to go. if (doMemMove) { memmove(((uint8_t *) packet) + currPacketOffset, firstEvent, (size_t) eventSize * 2); } else { doMemMove = true; // After first shrink always move memory. } currPacketOffset += (size_t) eventSize * 2; // Now go through remaining events and move their data close together. while (tsRun > 0) { uint8_t *thirdEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun--); memmove(((uint8_t *) packet) + currPacketOffset, thirdEvent, (size_t) eventTSOffset); currPacketOffset += (size_t) eventTSOffset; } } else { // Just copy data unchanged if no compression is possible. if (doMemMove) { uint8_t *startEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun); memmove(((uint8_t *) packet) + currPacketOffset, startEvent, (size_t) eventSize * tsRun); } currPacketOffset += (size_t) eventSize * tsRun; } // Reset values for next iteration. lastTS = currTS; tsRun = 1; } return (currPacketOffset); } #ifdef ENABLE_INOUT_PNG_COMPRESSION // Data compression technique 2: do PNG compression on frames, Grayscale and RGB(A). if ((state->format & 0x02) && caerEventPacketHeaderGetEventType(packet) == FRAME_EVENT) { size_t currPacketOffset = CAER_EVENT_PACKET_HEADER_SIZE; // Start here, no change to header. size_t frameHeaderSize = sizeof(struct caer_frame_event); CAER_FRAME_ITERATOR_ALL_START((caerFrameEventPacket) packet) size_t pixelSize = caerFrameEventGetPixelsSize(caerFrameIteratorElement); // Keep frame event header intact, compress image data, move memory close together. memmove(((uint8_t *) packet) + currPacketOffset, caerFrameIteratorElement, frameHeaderSize); currPacketOffset += frameHeaderSize; uint8_t *outBuffer; size_t outSize; if (!caerFrameEventPNGCompress(&outBuffer, &outSize, caerFrameEventGetPixelArrayUnsafe(caerFrameIteratorElement), caerFrameEventGetLengthX(caerFrameIteratorElement), caerFrameEventGetLengthY(caerFrameIteratorElement), caerFrameEventGetChannelNumber(caerFrameIteratorElement))) { // Failed to generate PNG. // Discard this frame event. currPacketOffset -= frameHeaderSize; continue; } // Check that the image didn't actually grow. // Add integer needed for storing PNG block length. if ((outSize + sizeof(int32_t)) > pixelSize) { caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString, "Failed to compress frame event. " "Image actually grew by %zu bytes to a total of %zu bytes.", (outSize - pixelSize), outSize); free(outBuffer); currPacketOffset -= frameHeaderSize; continue; } // Store size of PNG image block as 4 byte integer. int32_t outSizeInt = I32T(outSize); memcpy(((uint8_t *) packet) + currPacketOffset, &outSizeInt, sizeof(int32_t)); currPacketOffset += sizeof(int32_t); memcpy(((uint8_t *) packet) + currPacketOffset, outBuffer, outSize); currPacketOffset += outSize; // Free allocated PNG block memory. free(outBuffer); } return (currPacketOffset); } #endif return (packetSize); }
/* TextureToPng Inputs: data : This is an array of RGBA with 8 bits per channel. 4 bytes for each pixel. row_stride: Determines the amount of bytes per row of pixels. */ bool TextureToPng(u8* data, int row_stride, const std::string filename, int width, int height, bool saveAlpha) { bool success = false; if (!data) return false; char title[] = "Dolphin Screenshot"; char title_key[] = "Title"; png_structp png_ptr = NULL; png_infop info_ptr = NULL; // Open file for writing (binary mode) File::IOFile fp(filename, "wb"); if (!fp.IsOpen()) { PanicAlert("Screenshot failed: Could not open file %s %d\n", filename.c_str(), errno); goto finalise; } // Initialize write structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { PanicAlert("Screenshot failed: Could not allocate write struct\n"); goto finalise; } // Initialize info structure info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { PanicAlert("Screenshot failed: Could not allocate info struct\n"); goto finalise; } // Setup Exception handling if (setjmp(png_jmpbuf(png_ptr))) { PanicAlert("Screenshot failed: Error during png creation\n"); goto finalise; } png_init_io(png_ptr, fp.GetHandle()); // Write header (8 bit colour depth) png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_text title_text; title_text.compression = PNG_TEXT_COMPRESSION_NONE; title_text.key = title_key; title_text.text = title; png_set_text(png_ptr, info_ptr, &title_text, 1); png_write_info(png_ptr, info_ptr); // Write image data for (auto y = 0; y < height; ++y) { u8* row_ptr = (u8*)data + y * row_stride; u8* ptr = row_ptr; for (auto x = 0; x < row_stride / 4; ++x) { if (!saveAlpha) ptr[3] = 0xff; ptr += 4; } png_write_row(png_ptr, row_ptr); } // End write png_write_end(png_ptr, NULL); success = true; finalise: if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return success; }
/*! * 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( ImgGray *img, const char *filename ) { int width = img->Width(); int height = img->Height(); int bit_depth = 8; int color_type = PNG_COLOR_TYPE_GRAY; // to be changed to the correct value! /* create file */ FILE *fp = fopen(filename, "wb"); if (!fp) { dbg(DBG_ERROR,"[write_png_file] File %s could not be opened for writing", filename); return; } /* initialize stuff */ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { dbg(DBG_ERROR,"[write_png_file] png_create_write_struct failed"); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { dbg(DBG_ERROR,"[write_png_file] png_create_info_struct failed"); return; } if (setjmp(png_jmpbuf(png_ptr))) dbg(DBG_ERROR,"[write_png_file] Error during init_io"); png_init_io(png_ptr, fp); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) dbg(DBG_ERROR,"[write_png_file] Error during writing header"); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); int x,y; png_bytep *row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); for (y=0; y<height; y++) { row_pointers[y] = (png_byte*) malloc(width*sizeof(png_byte)); for (x=0;x<width;x++) { row_pointers[y][x] = (png_byte)(img->GetPixel(x,y)); } } /* write bytes */ if (setjmp(png_jmpbuf(png_ptr))) dbg(DBG_ERROR,"[write_png_file] Error during writing bytes"); png_write_image(png_ptr, row_pointers); /* end write */ if (setjmp(png_jmpbuf(png_ptr))) dbg(DBG_ERROR,"[write_png_file] Error during end of write"); png_write_end(png_ptr, NULL); /* cleanup heap allocation */ for (y=0; y<height; y++) { free( row_pointers[y]); } free( row_pointers ); fclose(fp); }
bool ImageMemory::_SavePngImage(const std::string &filename) const { // open up the file for writing FILE *fp = fopen(filename.c_str(), "wb"); if(fp == NULL) { IF_PRINT_WARNING(VIDEO_DEBUG) << "could not open file: " << filename << std::endl; return false; } // aah, RGB data! We can only handle RGBA at the moment if(rgb_format == true) { IF_PRINT_WARNING(VIDEO_DEBUG) << "attempting to save RGB format image data as a RGBA format PNG image" << std::endl; } // grab a write structure png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); if(!png_ptr) { IF_PRINT_WARNING(VIDEO_DEBUG) << "png_create_write_struct() failed for file: " << filename << std::endl; fclose(fp); return false; } // and a place to store the metadata png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { IF_PRINT_WARNING(VIDEO_DEBUG) << "png_create_info_struct() failed for file: " << filename << std::endl; png_destroy_write_struct(&png_ptr, NULL); fclose(fp); return false; } // prepare for error handling! if(setjmp(png_jmpbuf(png_ptr))) { IF_PRINT_WARNING(VIDEO_DEBUG) << "setjmp returned non-zero for file: " << filename << std::endl; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return false; } // tell it where to look png_init_io(png_ptr, fp); // write the header png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // get the row array from our data png_byte **row_pointers = new png_byte*[height]; int32 bytes_per_row = width * 4; for(uint32 i = 0; i < height; ++i) { row_pointers[i] = (png_byte *)pixels + bytes_per_row * i; } // tell it what the rows are png_set_rows(png_ptr, info_ptr, row_pointers); // and write the PNG png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); png_write_image(png_ptr, row_pointers); // clean up png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); // free the memory we ate delete[] row_pointers; // peace and love for all return true; } // bool ImageMemory::_SavePngImage(const std::string& filename) const
UInt64 PNGImageFileType::storeData(const Image *OSG_PNG_ARG (pImage ), UChar8 *OSG_PNG_ARG (buffer ), Int32 OSG_CHECK_ARG(memSize)) { #ifdef OSG_WITH_PNG png_structp png_ptr; png_infop info_ptr; if(pImage->getDimension() < 1 || pImage->getDimension() > 2) { FWARNING(("PNGImageFileType::write: invalid dimension %d!\n", pImage->getDimension())); return 0; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, &errorOutput, &warningOutput); if (png_ptr == NULL) { return 0; } /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); return 0; } BufferInfo bufferInfo; bufferInfo.buffer = buffer; bufferInfo.length = 0; png_set_write_fn(png_ptr, static_cast<void *>(&bufferInfo), user_write_data, user_flush_data); /* This is the hard way */ /* 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 */ Int32 ctype; switch(pImage->getPixelFormat()) { case Image::OSG_L_PF: ctype = PNG_COLOR_TYPE_GRAY; break; case Image::OSG_LA_PF: ctype = PNG_COLOR_TYPE_GRAY_ALPHA; break; #if defined(GL_BGR) || defined(GL_BGR_EXT) case Image::OSG_BGR_PF: #endif case Image::OSG_RGB_PF: ctype = PNG_COLOR_TYPE_RGB; break; #if defined(GL_BGRA) || defined(GL_BGRA_EXT) case Image::OSG_BGRA_PF: #endif case Image::OSG_RGBA_PF: ctype = PNG_COLOR_TYPE_RGB_ALPHA; break; default: FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n", pImage->getPixelFormat())); png_destroy_write_struct(&png_ptr, NULL); return 0; } Int32 bit_depth; switch (pImage->getDataType()) { case Image::OSG_UINT8_IMAGEDATA: bit_depth = 8; break; case Image::OSG_UINT16_IMAGEDATA: bit_depth = 16; break; default: FWARNING (("Invalid pixeldepth, cannot store data\n")); return 0; }; png_set_IHDR(png_ptr, info_ptr, pImage->getWidth(), pImage->getHeight(), bit_depth, ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ /* note that if sRGB is present the gAMA and cHRM chunks must be ignored * on read and must be written in accordance with the sRGB profile */ /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); #if BYTE_ORDER == LITTLE_ENDIAN if (bit_depth == 16) png_set_swap(png_ptr); #endif if(pImage->getPixelFormat() == Image::OSG_BGR_PF || pImage->getPixelFormat() == Image::OSG_BGRA_PF) { /* flip BGR pixels to RGB */ png_set_bgr(png_ptr); /* swap location of alpha bytes from ARGB to RGBA */ png_set_swap_alpha(png_ptr); } /* The easiest way to write the image (you may have a different memory * layout, however, so choose what fits your needs best). You need to * use the first method if you aren't handling interlacing yourself. */ png_bytep *row_pointers = new png_bytep [pImage->getHeight()]; for(Int32 k = 0; k < pImage->getHeight(); k++) { row_pointers[k] = (const_cast<UInt8 *>(pImage->getData())) + (pImage->getHeight() - 1 - k) * pImage->getWidth() * pImage->getBpp(); } /* write out the entire image data in one call */ png_write_image(png_ptr, row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); /* clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); delete [] row_pointers; /* that's it */ return bufferInfo.length; #else SWARNING << getMimeType() << " storeData is not compiled into the current binary " << std::endl; return 0; #endif }
//----------------------------------------------------------------------------- bool abiword_document::garble_png( void*& data, size_t& size ) { png_bytep * dib; png_uint_32 width; png_uint_32 height; int compression_type; int filter_type; int interlace_type; int bit_depth; int color_type; png_uint_32 rowbytes; // read PNG data { png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (void*) NULL, NULL, NULL ); if (!png_ptr) return false; png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct( &png_ptr, (png_infopp)NULL, (png_infopp)NULL ); return false; } png_read_data _png_read_data = { data, size, 0 }; png_set_read_fn( png_ptr, (void*)&_png_read_data, &_png_read ); png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type ); png_set_packing( png_ptr ); png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_gray_to_rgb( png_ptr ); png_set_strip_alpha( png_ptr ); png_set_interlace_handling( png_ptr ); png_set_bgr( png_ptr ); rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_destroy_read_struct( &png_ptr, &info_ptr, NULL ); } // we don't care about the image data itself, we just want a random garbled // image of the same size dib = (png_bytep*) malloc( sizeof(png_bytep) * height ); for (size_t i=0; i<height; ++i) { dib[i] = (png_byte*) malloc( rowbytes ); garble_image_line( reinterpret_cast<char*>( dib[i] ), rowbytes ); } bool result = false; { // write it back png_structp png_ptrw = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if (png_ptrw) { png_infop info_ptrw = png_create_info_struct( png_ptrw ); png_set_IHDR( png_ptrw, info_ptrw, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type ); string newdata; png_set_write_fn( png_ptrw, (void*)&newdata, &_png_write, NULL ); png_write_info( png_ptrw, info_ptrw ); png_write_image( png_ptrw, dib ); png_write_end( png_ptrw, NULL ); png_destroy_write_struct( &png_ptrw, NULL ); free(data); size = newdata.size(); data = malloc( size ); memcpy( data, &newdata[0], size ); result = true; } } // cleanup for (size_t i=0; i<height; i++) free( dib[i] ); free( dib ); return result; }